【发布时间】:2018-06-07 12:52:45
【问题描述】:
上下文:在最近的一次对话中,问题是“gcc/clang 在编译时是否执行strlen("static string")?”上来了。经过一些测试,答案似乎是肯定的,无论优化程度如何。即使在-O0 看到这个我有点惊讶,所以我做了一些测试,最终得到了以下代码:
#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;
}
令我惊讶的是,它打印的是 4 10 而不是 10 10。我尝试使用gcc 和clang 以及各种标志(-pedantic、-O0、-O3、-std=c89、-std=c11,...)进行编译,并且测试之间的行为是一致的。
由于我没有包含string.h,因此我希望使用我对strlen 的定义。但汇编代码确实表明strlen("abcd") 基本上被return 4 取代(这是我在运行程序时观察到的)。
此外,编译器不会打印带有-Wall -Wextra 的警告(更准确地说,与问题无关:他们仍然警告我的strlen 定义中未使用参数s)。
出现了两个(相关的)问题(我认为它们足够相关,可以在同一个问题中提出):
- 当标头声明不包含时,是否允许在 C 中重新定义标准函数?
- 这个程序的行为是否应有尽有?如果是这样,具体会发生什么?
【问题讨论】:
-
如果你用
gcc -Wall -Wstrict-prototypes -Werror编译上面的代码,它会给出类似函数声明不是原型这样的错误,所以我想你提到的一点是当标头声明不包含时,它允许在 C 中重新定义标准函数吗? -
@achal 哦,我不知道
-Wstrict-prototypes,谢谢,我学到了一些东西。但是,如果我使用void作为f和main的参数来删除这些警告,程序的行为不会改变(它仍然打印4 10),所以我不确定我是否理解您评论的最后一部分。 -
我猜
strlen("abcd")显然是一个常量,编译器已将其替换为值 4,因为它可以识别strlen()。 IOTHg("abcd")不是 显然 常量,因此编译器会发出调用您的strlen()函数的代码(但尝试将 g() 和 strlen() 声明为静态内联)。 -
出于险恶目的重用标准库函数名会调用未定义的行为。
标签: c gcc compilation clang