Reputation: 9749
I am working on a C math library, and it is using macros do to the most of it's work, I am now facing a problem.
This is what the macro looks like:
the_macro(a, b, c)
and the macro itself does something like:
(a - b > 0) ? error_function : 1
the error_function is used to stop the user at complie time, so if (a - b > 0)
is true
, then the macro will expand as a function which does not have a definition. So this will cause a linkage error.
Everthing seems good, but today my boss told me we need to do some unit-test, so I wrote a function which wraps the macro:
int my_func(int a, int b, int c)
{
return the_macro(a, b, c);
}
here comes the problem, the code can't pass linkage, because if I use a var instead of a constant to call the_macro, these error_functions
will be in the .o
file, because the int a, int b, int c
are all known at runtime, so I can only call the macro function with constants: the_macro(2, 3, 4)
is there any way to avoid this? or is there a better solution to do unit-test on this macro?
EDIT:
The code I'm working on is confidential... but I made an example which demonstrates the problem:
#include <stdio.h>
#define the_macro(a, b)\
(a > b)?error_function():1
// Comment out my_func(), then the program will run normaly
// But if you don't comment it out, the linkage error will come out.
void my_func(int a, int b)
{
the_macro(a, b);
}
int main()
{
printf("%d\n", the_macro(1, 10));
return 0;
}
I'm using gcc-4
Upvotes: 0
Views: 117
Reputation: 10658
Let's see if I understand this correctly:
You want a way to break compilation if a-b>0
? This is actually impossible unless you use C11. There simply is no way to have the compiler abort depending on a condition. In your case you are trying to use a combination of the optimizer and the linker to get the desired behavior. But this cannot work reliably.
The expression (a - b > 0) ? error_function : 1
may be reduced by the optimizer to one if a-b>0, but this is not guaranteed. There is a guaranteed behavior compiler has to show defined by the C standard and this standard does not mention an optimizer. The same optimizer may sometimes reduce the expression, and sometimes not reduce it depending on other things in your code. Or it may or may not reduce it depending on the command line flags you are passing.
So with using this macro you are writing code, which may suddenly break unexpectedly when you switch compiler, compiler version, operating system, add or remove linked libraries or target architecture. Code that suddenly breaks depending on such changes is very bad. Don't do this to your fellow developers.
Better to write portable code for which you can be sure that future compilers will understand it because it follows the standard. In pre C11 there is no way to do this. If you really need this, tell your boss the only way is to use C11 which has a static_assert
keyword which can give you the conditional abortion of the compilation.
Upvotes: 1
Reputation: 10497
For the purposes of your unit tests (only) why not define error_function()
as part of your unit test and have it return an error unconditionally that your test framework can detect. That way you should be able to mimic the behaviour you're seeing at compile time using either constants or variables.
It's not exactly what you want, but unit test frameworks are always, by their nature run-time testing mechanisms, so an automated compile time test is probably not going to be possible.
Alternatively, you could use system()
to run a command line build including your library, redirect the output, including errors into a file. You could then open the file and scan for known text of the linkage error.
Upvotes: 1
Reputation: 153957
Regardless of where you use the macro, if error_function
is not declared, you should get a compiler error. If it is declared but not defined, you have undefined behavior. Whether the arguments to the macro are constants or not changes nothing in this respect. (It may affect what the actual behavior is in the case of undefined behavior.)
Upvotes: 4
Reputation: 3119
When you call the macro with constants, the compiler knows the value and thus, perhaps as as optimization, the expression the_macro (5, 4, 0)
gets replaced by 1
instead of error_function
. When your expression a-b
evaluates to <= 0
, your compiler replaces it with error_function
, and stops your compilation.
On the other hand, when you use variables, the compiler doesn't know the result of the expression and has to use the full expansion of the macro, which contains a call to undefined function, and hence you get the linkage error.
Upvotes: 2