【问题标题】:Why does not execute printf inside function?为什么不在函数内部执行 printf?
【发布时间】:2018-03-13 05:19:33
【问题描述】:

以下代码在 GCC 编译器上编译运行。

#include <stdio.h>

 int arr[10];

 int func()
 {
      printf("In func\n");
      return 0;
 }

int main() 
{
    if (&arr[func()])
        printf("In main\n");
     return 0;
}

输出:

In main

为什么不执行printf("In func\n");

【问题讨论】:

  • 这行代码有什么作用if (&amp;arr[func()])arr 的任何元素的地址何时会为零?您确定您的代码中没有 DOS 控制字符吗?收到任何编译器警告?什么?
  • 或者至少确保您在发布代码后已经“保存”,然后在启用警告的情况下进行编译并继续。
  • 我刚刚粘贴了你的代码并得到了In func/In main。 (gcc 5.4.0)
  • @BasileStarynkevitch 这确实是一个 gcc 问题。在 gcc 7.3 中,func() 完全优化了 main()。即使它产生输出。早期版本的 gcc 可以很好地处理它。真的很奇怪。 .string "In func" 被存储,func() 函数在那里,但在 main: 的代码生成中完全省略了它所以 @Jayesh 并不疯狂。
  • 请说明您是否知道@PkmX 在他们的回答中提供的链接内容。代码示例的相似性是惊人的。如果您尝试测试 StackOverflowers,我投票支持 PkmX。

标签: c arrays function gcc


【解决方案1】:

最新 gcc 的各种组合似乎存在一个微妙的问题,无论是有意的还是无意的。 Archlinux 上最新内核 4.15.8 上的 7.3 版。无论出于何种原因,为main() 生成的代码都省略了对func() 的调用。例如

$ gcc -S -masm=intel -o infunc2.asm infunc2.c

生成的程序集是:

$ cat infunc2.asm
        .file   "infunc2.c"
        .intel_syntax noprefix
        .text
        .comm   arr,40,32
        .section        .rodata
.LC0:
        .string "In func"
        .text
        .globl  func
        .type   func, @function
func:
.LFB0:
        .cfi_startproc
        push    rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        mov     rbp, rsp
        .cfi_def_cfa_register 6
        lea     rdi, .LC0[rip]
        call    puts@PLT
        mov     eax, 0
        pop     rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   func, .-func
        .section        .rodata
.LC1:
        .string "In main"
        .text
        .globl  main
        .type   main, @function
main:
.LFB1:
        .cfi_startproc
        push    rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        mov     rbp, rsp
        .cfi_def_cfa_register 6
        lea     rdi, .LC1[rip]
        call    puts@PLT
        mov     eax, 0
        pop     rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1:
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.0"
        .section        .note.GNU-stack,"",@progbits

请注意,对func() 的调用在上面标记为.LFB0:main: 的过程根本不调用func.LFB0:,尽管它存在,尽管"In func" 字符串存在于.LC0: 中。我怀疑这不是预期的行为。

比如简单编译不优化-O0函数不被调用,例如:

$ gcc -g -O0 -o bin/if2 infunc2.c
$ ./bin/if2
In main

更改代码以存储arr[func()] 的地址确实会强制调用func(),例如

#include <stdio.h>

int arr[10];

int func()
{
    printf ("In func\n");
    return 0;
}

int main (void)
{
    int *p = &arr[func()];
    if (p)
        printf("In main\n");
    return 0;
}

然后

$ gcc -Wall -Wextra -pedantic -std=gnu11 -Ofast -o bin/infunc infunc.c
$ ./bin/infunc
In func
In main

并且生成的程序集支持不同的行为:

$ gcc -S -masm=intel -o infunc.asm infunc.c

$ cat infunc.asm
        .file   "infunc.c"
        .intel_syntax noprefix
        .text
        .comm   arr,40,32
        .section        .rodata
.LC0:
        .string "In func"
        .text
        .globl  func
        .type   func, @function
func:
.LFB0:
        .cfi_startproc
        push    rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        mov     rbp, rsp
        .cfi_def_cfa_register 6
        lea     rdi, .LC0[rip]
        call    puts@PLT
        mov     eax, 0
        pop     rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   func, .-func
        .section        .rodata
.LC1:
        .string "In main"
        .text
        .globl  main
        .type   main, @function
main:
.LFB1:
        .cfi_startproc
        push    rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        mov     rbp, rsp
        .cfi_def_cfa_register 6
        sub     rsp, 16
        mov     eax, 0
        call    func
        cdqe
        lea     rdx, 0[0+rax*4]
        lea     rax, arr[rip]
        add     rax, rdx
        mov     QWORD PTR -8[rbp], rax
        cmp     QWORD PTR -8[rbp], 0
        je      .L4
        lea     rdi, .LC1[rip]
        call    puts@PLT
.L4:
        mov     eax, 0
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1:
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.0"
        .section        .note.GNU-stack,"",@progbits

我希望我能对这里的处理提供一些合乎逻辑的解释,但我只能记录下来。看来我们需要和 gcc 名单上的人谈谈。


在 'if' 内部的地址计算中丢弃的副作用

这似乎是 gcc 中的一种回归,取决于单个发行版是否应用了足够的补丁来掩盖它。这是工作中的 gcc 错误。 Bug 84607

【讨论】:

  • 您应该报告您的 Linux 发行版上的错误。顺便说一句,在 Debian/Sid 上我没有观察到。
  • 这也可以解释最近发行版 :( 的一些无法解释的问题。感谢您的反馈。
  • 也许你的发行版有一些奇怪的规范文件,迫使一些优化
  • 我认为这只是 Arch 上 gcc 行中某处的纯粹回归。今天 Arch 列表上有几个无法解释的错误(一个我的),无论是什么导致了这似乎都是问题的完美候选者。 “休斯顿——我们有个问题……”
【解决方案2】:

这是一个 gcc 错误 (#84607),已在 gcc 7.3.1 或更高版本中修复。

【讨论】:

  • 这似乎是问题中代码引用的基本思想的来源。
【解决方案3】:

问题在于您的编译。我使用 gcc 编译。我这样编译你的文件:

gcc main.c -o prog
./prog
In func
In main

我觉得不错。如果您使用与 gcc 不同的编译器,请检查如何使用您的编译器进行编译的过程。我也使用 gcc 7.3

【讨论】:

  • 在 GCC 7.3 中,-O-O2-O3 也会发生相同的输出。
  • Mac 上的 GCC 7.3.0 为我显示了该错误(此版本和 GCC 错误 #84607 中的版本都带有 -O0-O1-O2-O3
猜你喜欢
  • 2017-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 2020-07-02
相关资源
最近更新 更多