【发布时间】:2021-07-02 16:11:18
【问题描述】:
我认为我发现 gcc 编译器处理函数的方式存在问题。
我不知道这是一个错误,还是我多年来一直放过的东西从不分心。 在实践中,通过声明一个函数并定义后者具有返回值,编译器将分配在函数范围内的第一个变量的值存储在 EAX 寄存器中,然后将其依次存储在变量中。示例:
#include<stdio.h>
int add(int a, int b)
{
int c = a + b;
;there isn't return
}
int main(void)
{
int res = add(3, 2);
return 0;
}
这是输出:
5
这是带有 intel 语法的 x86-64 程序集:
功能添加:
push rbp
mov rbp, rsp
mov DWORD PTR[rbp-0x14], edi ;store first
mov DWORD PTR[rbp-0x18], esi ;store second
mov edx, DWORD PTR[rbp-0x14]
mov eax, DWORD PTR[rbp-0x18]
add eax, esx
mov DWORD PTR[rbp-0x4], eax
nop
pop rbp
ret
主要功能:
push rbp
mov rbp, rsp
sub rsp, 0x10
mov esi, 0x2 ;first parameter
mov edi, 0x3 ;second parameter
call 0x1129 <add>
;WHAT??? eax = a + b, why store it?
mov DWORD PTR[rbp-0x4], eax
mov eax, 0x0
leave
ret
如您所见,它在变量c 中保存了参数a 和b 的总和,但随后将我保存在变量res 包含它们总和的eax 寄存器中,好像函数返回值。
这是因为函数是用返回值定义的吗?
【问题讨论】:
-
您希望发生什么?
-
因为函数没有返回值,所以我省略了“return”,我希望变量“c”的内容会丢失,因此在 nesusno mod 中 eax 的内容(eax = a + b) 存储在“res”中。我再说一遍,我省略了“return”,neinte“return c”或“return a + b”
-
好的,我明白了,谢谢
-
确保始终使用
-Wall,您会从编译器收到消息:“控制到达非无效函数的末尾”。我认为这是警告而不是错误的唯一原因是标准要么不想强制编译器进行所需的分析以检测到这一点,要么可能不想指定所需的实际分析. -
@ErikEidt:在 C 语言中,只要调用者不使用返回值,行为就已经明确。这是为了与
void之前的 pre-ANSI C 向后兼容,并且存在原型,因此存在从非 void 函数末尾脱落的现有代码。即使对于 C99/C11 也没有取缔它。在 ISO C++ 中,它是 未定义的行为,以便执行从非 void 函数的末尾脱落,因此即使没有 -Wall,g++也会发出警告,并为此省略 code-gen执行路径(甚至不是ret,只是在 asm 中从字面上掉下来!)godbolt.org/z/e54qnKr7q
标签: c assembly gcc undefined-behavior