覆盖标准函数会出现意外行为

时间:2016-07-01 09:34:53

标签: c

[更新] 2016.07.02

的main.c

#include <stdio.h>
#include <string.h>

size_t strlen(const char *str) {
    printf("%s\n", str);
    return 99;
}
int main() {
    const char *str = "AAA";
    size_t a = strlen(str);
    strlen(str);
    size_t b = strlen("BBB");
    return 0;
}

预期输出

AAA
AAA
BBB

使用gcc -O0 -o main main.c编译:

AAA

使用gcc -O3 -o main main.c编译

AAA
AAA

带有标志-O0

的相应asm代码
000000000040057c <main>:
40057c: 55                      push   %rbp
40057d: 48 89 e5                mov    %rsp,%rbp
400580: 48 83 ec 20             sub    $0x20,%rsp
400584: 48 c7 45 e8 34 06 40    movq   $0x400634,-0x18(%rbp)
40058b: 00 
40058c: 48 8b 45 e8             mov    -0x18(%rbp),%rax
400590: 48 89 c7                mov    %rax,%rdi
400593: e8 c5 ff ff ff          callq  40055d <strlen>
400598: 48 89 45 f0             mov    %rax,-0x10(%rbp)
40059c: 48 c7 45 f8 03 00 00    movq   $0x3,-0x8(%rbp)
4005a3: 00 
4005a4: b8 00 00 00 00          mov    $0x0,%eax
4005a9: c9                      leaveq 
4005aa: c3                      retq   
4005ab: 0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

和-O3:

0000000000400470 <main>:
400470: 48 83 ec 08             sub    $0x8,%rsp
400474: bf 24 06 40 00          mov    $0x400624,%edi
400479: e8 c2 ff ff ff          callq  400440 <puts@plt>
40047e: bf 24 06 40 00          mov    $0x400624,%edi
400483: e8 b8 ff ff ff          callq  400440 <puts@plt>
400488: 31 c0                   xor    %eax,%eax
40048a: 48 83 c4 08             add    $0x8,%rsp
40048e: c3                      retq   

使用标志-O0,为什么对strlen的第二次和第三次调用没有调用用户定义的strlen?

使用-O3,为什么对strlen的第三次调用已被优化?

2 个答案:

答案 0 :(得分:1)

GCC承认strlen()有内置内容并将其替换为内置内容。因此,您的strlen()版本不会被调用。

我使用-fno-builtin编译了您的代码,这会禁用内置内容,我从第一次和第三次Log in strlen调用中获得两次strlen()输出。可能第二个strlen()被优化掉了,因为它的返回值没有被使用。这可能发生在之前 GCC认识到它不能使用内置strlen()。否则,它无法优化第二次strlen()通话,因为它具有打印消息的副作用

同样,如果将第二次strlen()调用的结果存储为:

size_t b = strlen(str); // call 2

然后我看,&#34;登录strlen()&#34;打印3次。

如果我使用-O3编译(有或没有-fno-builtin),我根本就没有输出,因为如前所述,GCC优化了整个 程序

这不是GCC的问题,因为重新定义标准函数在技术上是undefined behaviour,因此GCC可以自由处理它。

答案 1 :(得分:0)

默认情况下可能启用内置功能。如果您明智地调用用户定义函数,则更改strlen function.So,

的返回类型 strlen_adder.h

中的

int strlen(const char*);
strlen_adder.c

中的

int strlen(const char *s)

同时删除#include<string.h>文件中的main.c