alenyw
alenyw

Reputation: 41

gcc optimizations: how to deal with macro expantion in strncmp & other functions

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

Answers (1)

Armali
Armali

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

Related Questions