从标准库重新定义函数 [英] Redefining function from standard library

查看:14
本文介绍了从标准库重新定义函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文:在最近的对话中,问题gcc/clang 在编译时执行 strlen("static string") 吗?上来了.经过一些测试,无论优化水平如何,答案似乎都是肯定的.看到这甚至在 -O0 完成我有点惊讶,所以我做了一些测试,最终得到了以下代码:

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
",f(),g("abcd"));
  return 0;
}

令我惊讶的是,它打印的是 4 10 而不是 10 10.我尝试使用 gccclang 以及各种标志(-pedantic-O0-O3, -std=c89, -std=c11, ...) 并且测试之间的行为是一致的.

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.

因为我没有包含 string.h,所以我希望使用我对 strlen 的定义.但是汇编代码确实显示strlen("abcd") 基本上被return 4 替换了(这是我在运行程序时观察到的).

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).

此外,编译器不会打印带有 -Wall -Wextra 的警告(更准确地说,与问题无关:他们仍然警告参数 s 在我的定义中未使用strlen).

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).

出现两个(相关)问题(我认为它们足够相关,可以在同一问题中提出):
- 是否允许在声明不包含标准函数的头文件中重新定义 C 中的标准函数?
- 该程序是否按其应有的方式运行?如果是这样,究竟会发生什么?

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?

推荐答案

Per C 2011(草案 N1570)7.1.3 1 和 2:

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.

如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的情况除外),或将保留标识符定义为宏名称,则行为未定义.

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.

以下子条款"指定了标准 C 库,包括 strlen.你的程序定义了 strlen,所以它的行为是未定义的.

The "following subclauses" specify the standard C library, including strlen. Your program defines strlen, so its behavior is undefined.

你观察到的情况是:

  • 编译器知道 strlen 应该如何表现,而不管您的定义如何,因此,在优化 f 中的 strlen("abcd") 时code>,它在编译时计算 strlen,结果为 4.
  • g("abcd")中,编译器无法识别,因为g的定义,这相当于strlen(";abcd"),因此它不会在编译时对其进行优化.相反,它将它编译为对 g 的调用,并将 g 编译为调用 strlen,它还编译您对 的定义strlen,结果 g("abcd") 调用 g,它调用你的 strlen,它返回 10.
  • The compiler knows how strlen is supposed to behave, regardless of your definition, so, while optimizing strlen("abcd") in f, it evaluates strlen at compile time, resulting in four.
  • In g("abcd"), the compiler fails to recognize that, because of the definition of g, this is equivalent to strlen("abcd"), so it does not optimize it at compile time. Instead, it compiles it to a call to g, and it compiles g to call strlen, and it also compiles your definition of strlen, with the result that g("abcd") calls g, which calls your strlen, which returns ten.

C 标准将允许编译器完全丢弃您对 strlen 的定义,因此 g 返回四个.然而,一个好的编译器应该警告你的程序定义了一个保留标识符.

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.

这篇关于从标准库重新定义函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆