Reputation: 41
Take this sample code:
#include <string.h>
#define STRcommaLEN(str) (str), (sizeof(str)-1)
int main() {
const char * b = "string2";
const char * c = "string3";
strncmp(b, STRcommaLEN(c));
}
If you don't use optimizations in GCC, all is fine, but if you add -O1 and above, as in gcc -E -std=gnu99 -Wall -Wextra -c -I/usr/local/include -O1 sample.c
, strncmp
becomes a macro, and in preprocessing stage STRcommaLen is not expanded. In fact in resulting "code" strncmp
's arguments are completely stripped.
I know if I add #define NEWstrncmp(a, b) strncmp (a, b)
and use it instead, the problem goes away. However, mapping your own functions to every standard function that may become a macro doesn't seem like a great solution.
I tried finding the specific optimization that is responsible for it and failed. In fact if I replace -O1 with all the flags that it enables according to man gcc
, the problem goes away. My conclusion is that -O1 adds some optimizations that are not controlled by flags and this is one of them.
How would you deal with this issue in a generic way? There may be some macro magic I am not familiar with or compiler flags I haven't looked at? We have many macros and a substantial code base - this code is just written to demonstrate one example.
Btw, GCC version/platform is gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
.
Thanks, Alen
Upvotes: 2
Views: 526
Reputation: 19395
You correctly noted that
in preprocessing stage STRcommaLen is not expanded
- more precisely, not before the strncmp
macro gets expanded. This inevitably leads to an error you probably overlooked or forgot to mention:
sample.c:7:30: error: macro "strncmp" requires 3 arguments, but only 2 given
Your conclusion
that -O1 adds some optimizations that are not controlled by flags and this is one of them
is also right - this is controlled by the macro __OPTIMIZE__
which apparently gets set by -O1
.
If I'd do something like that (which I probably wouldn't, in respect of the pitfall you demonstrated by using sizeof
a char *
), I'd still choose
mapping your own functions to every standard function that may become a macro
- but rather like
#include <string.h>
#define STRNCMP(s1, s2) strncmp(s1, s2, sizeof(s2)-1)
int main()
{
const char b[] = "string2";
const char c[] = "string3";
STRNCMP(b, c);
}
Upvotes: 1