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

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

问题描述

上下文:在最近的一次对话中,问题在编译时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\n",f(),g("abcd"));
  return 0;
}

令我惊讶的是,它会显示 4 10 而不是 10 10 。我尝试使用 gcc clang 以及各种标志( -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).

出现两个(相关)问题(我认为它们之间的相关性足以在同一个问题中提出):

-是否可以重新定义
-此程序的行为是否应做?如果是这样,究竟发生了什么?

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?

推荐答案

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

在您观察到的情况下,发生的事情是:

What is happening in the case you observe is:


  • 编译器知道 strlen 的行为方式,而不管您的定义如何,因此在优化 $ f 中的strlen( abcd),在编译时评估 strlen ,结果为四个。

  • g( abcd)中,由于 g ,它等效于 strlen( abcd),因此它不会在编译时对其进行优化。相反,它将其编译为对 g 的调用,并且将其编译为 g 来调用 strlen ,它还会编译您的 strlen 定义,结果是 g( abcd)调用 g ,这将调用您的 strlen ,并返回十。

  • 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天全站免登陆