1

以下是 GCC 变量属性扩展的示例代码,

#include<stdio.h>
int main(void){
        int sam __attribute__((unused))= 10;
        int p = sam+1;
        printf("\n%d" , p);
}

对于使用以下程序生成的上述程序的汇编代码:

gcc -S sample.c

.s 文件中不包含变量 sam,而程序的输出是“11”,这是正确的。那么编译器是否完全忽略了未使用的变量而不将其输出到可执行文件中?如果是这样,为什么程序的输出正确?谁能解释 gcc 中未使用和使用的变量属性的工作原理。

谢谢

4

2 回答 2

1

编译器是否完全忽略了未使用的变量

取决于你所说的“忽视”是什么意思。编译器会优化代码,但不会完全忽略变量,否则编译器无法计算结果。

不在可执行文件中输出?

是的。

如果是这样,为什么程序的输出正确?

因为这是编译器所做的 - 使用编程语言描述的输出生成程序。代码不是 1:1 的汇编,代码是一种描述程序行为的语言。理论上,只要编译后的程序的输出与源代码中的内容是正确的,编译器就可以生成它想要的任何汇编指令。

您可能想在 C 编程语言的上下文中研究术语副作用as-if 规则

谁能解释 gcc 中未使用和使用的变量属性的工作原理。

GCC 文档中没有关于变量属性的更好解释:

没用过

附加到变量的此属性意味着该变量可能未被使用。GCC 不会对此变量产生警告。

用过的

此属性附加到具有静态存储的变量,意味着即使看起来未引用该变量,也必须发出该变量。

当应用于 C++ 类模板的静态数据成员时,该属性还意味着如果类本身被实例化,则该成员被实例化。

该属性unused是从警告中消除编译器-Wunused-*警告。

该属性used旨在用于变量(但我认为也适用于函数),以便将变量生成到汇编代码中。即使它没有在任何地方使用。

于 2021-02-16T13:24:29.380 回答
1

尝试不优化编译

gcc -O0 sample.c -S -masm=intel

生成的汇编代码

    .file   "sample.c"
    .intel_syntax noprefix
    .text
    .def    __main; .scl    2;  .type   32; .endef
    .section .rdata,"dr"
.LC0:
    .ascii "\12%d\0"
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    push    rbp
    .seh_pushreg    rbp
    mov rbp, rsp
    .seh_setframe   rbp, 0
    sub rsp, 48
    .seh_stackalloc 48
    .seh_endprologue
    call    __main
    mov DWORD PTR -4[rbp], 10
    mov eax, DWORD PTR -4[rbp]
    add eax, 1
    mov DWORD PTR -8[rbp], eax
    mov eax, DWORD PTR -8[rbp]
    mov edx, eax
    lea rcx, .LC0[rip]
    call    printf
    mov eax, 0
    add rsp, 48
    pop rbp
    ret
    .seh_endproc
    .ident  "GCC: (GNU) 10.2.0"
    .def    printf; .scl    2;  .type   32; .endef
于 2021-02-16T12:47:33.377 回答