问题
Context: In a recent conversation, the question "does gcc/clang do strlen("static string") at compile time?" came up. After some testing, the answer seems to be yes, regardless the level of optimization. I was a bit surprised to see this done even at -O0, so I did some testing, and eventually arrived to the following code:
#include <stdio.h>
unsigned long strlen(const char* s) {
return 10;
}
unsigned long f() {
return strlen("abcd");
}
unsigned long g(const char* s) {
return strlen(s);
}
int main() {
printf("%ld %ld\n",f(),g("abcd"));
return 0;
}
To my surprise, it prints 4 10 and not 10 10. I tried compiling with gcc and clang, and with various flags (-pedantic, -O0, -O3, -std=c89, -std=c11, ...) and the behavior is consistent between the tests.
Since I didn't include string.h, I expected my definition of strlen to be used. But the assembly code shows indeed that strlen("abcd") was basically replaced by return 4 (which is what I'm observing when running the program).
Also, the compilers print no warnings with -Wall -Wextra (more precisely, none related to the issue: they still warn that parameter s is unused in my definition of strlen).
Two (related) questions arise (I think they are related enough to be asked in the same question):
- is it allowed to redefine a standard function in C when the header declaring it isn't included?
- does this program behave as it should? If so, what happens exactly?
回答1:
Per C 2011 (draft N1570) 7.1.3 1 and 2:
All identifiers with external linkage in any of the following subclauses … are always reserved for use as identifiers with external linkage.
If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.
The “following subclauses” specify the standard C library, including strlen. Your program defines strlen, so its behavior is undefined.
What is happening in the case you observe is:
- The compiler knows how
strlenis supposed to behave, regardless of your definition, so, while optimizingstrlen("abcd")inf, it evaluatesstrlenat compile time, resulting in four. - In
g("abcd"), the compiler fails to recognize that, because of the definition ofg, this is equivalent tostrlen("abcd"), so it does not optimize it at compile time. Instead, it compiles it to a call tog, and it compilesgto callstrlen, and it also compiles your definition ofstrlen, with the result thatg("abcd")callsg, which calls yourstrlen, which returns ten.
The C standard would allow the compiler to discard your definition of strlen completely, so that g returned four. However, a good compiler should warn that your program defines a reserved identifier.
来源:https://stackoverflow.com/questions/50741722/redefining-function-from-standard-library