Dad*_*ada 7 c gcc compilation clang
上下文:在最近的一次对话中,问题是"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;
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,它打印4 10而不是10 10.我试着用编译gcc和clang,并用各种标志(-pedantic,-O0,-O3,-std=c89,-std=c11,...)和行为测试之间是一致的.
由于我没有包含string.h,我希望我的定义strlen可以使用.但汇编代码确实显示strlen("abcd")基本上被替换为return 4(这是我在运行程序时观察到的).
此外,编译器不打印任何警告-Wall -Wextra(更确切地说,没有与问题相关:他们仍然警告s我的定义中没有使用参数strlen).
出现了两个(相关的)问题(我认为它们足够相关,可以在同一个问题中提出):
- 当标题声明不包括在内时,是否允许在C中重新定义标准函数?
- 这个程序的行为应该如何吗?如果是这样,究竟会发生什么?
Per C 2011(草案N1570)7.1.3 1和2:
在以下任何子条款中具有外部链接的所有标识符...始终保留用作具有外部链接的标识符.
如果程序在保留它的上下文中声明或定义标识符(除了7.1.4允许的标识符),或者将保留标识符定义为宏名称,则行为是未定义的.
"以下子条款"指定标准C库,包括strlen.您的程序定义strlen,因此其行为未定义.
你观察到的情况是:
strlen无论您的定义如何,编译器都知道应该如何表现,因此,在优化strlen("abcd")时f,它会strlen在编译时进行评估,从而产生四个.g("abcd"),编译器无法识别,由于其定义g,这相当于strlen("abcd"),因此它不会在编译时对其进行优化.相反,它将它编译为一个调用g,并编译g为调用strlen,它还编译你的定义strlen,结果g("abcd")调用g,调用你的strlen,返回十.C标准将允许编译器完全丢弃您的定义strlen,以便g返回四个.但是,一个好的编译器应该警告你的程序定义了一个保留的标识符.
| 归档时间: |
|
| 查看次数: |
228 次 |
| 最近记录: |