当return类型在函数头中默认并且没有提供return语句时,为什么会发生未定义的行为?
When return type is default in function header and return statement is not provided, why is undefined behavior happening?
当我在 GCC 中执行以下程序时,我希望输出为 0,因为 max() 函数中缺少 return 语句,但是当我执行它时,输出为 10。什么是这种行为的原因??
#include <stdio.h>
max(int x, int y)
{
if (x > y)
return x;
else
x=5;
}
int main(void)
{
int a = 10, b = 20;
// Calling above function to find max of 'a' and 'b'
int m = max(a, b);
printf("%d", m);
}
When I execute the following program in GCC
你没有在编译器中执行某些东西!
你用 gcc 编译你的代码!
I expect output to be 0 because the return statement is missing
您的期望完全错误。 C 和 C++ 都具有“在缺少 return 语句的情况下的默认 return 值”因此,如果您的函数未定义 void
且值为让你的程序格式正确!
每个编译器都会至少给你一个警告。您应该始终使用 -Wall 或更好的 -Wextra -pedantic 进行编译。
When return type is default in function header and return statement is not provided, why is undefined behavior happening?
因为标准没有定义应该发生什么。因此,朗朗上口的术语“未定义的行为”。如果标准没有定义应该发生什么......那么实际上任何事情都可能发生,代码可以以任何方式运行。
中明确指出您的代码具有未定义的行为
What is the reason for such behavior??
由于未定义行为,因此不需要编译器生成具有任何可预测行为的代码。所以它会生成一些代码,这些代码恰好起作用 as-if 该函数会返回 10,但没有人真正关心,因为它可以做它想做的事。
实用的答案来自检查生成的程序集 from the compiler (godbolt link)(编译器可以做它想做的事)。在 main
函数编译器中放置 mov DWORD PTR [rbp-4], 10
然后 mov eax, DWORD PTR [rbp-4]
然后 mov edi, eax
- 即。 edi
寄存器有 10
。然后在 max
中,编译器执行 mov DWORD PTR [rbp-4], edi
和 mov eax, DWORD PTR [rbp-4]
,然后 ret
urns 来自函数 - 当 max
returns 时,[=21= 的内容] 寄存器有 10
。因为编译器使用 mov esi, eax
来初始化 printf
的参数,printf
函数打印值 10
,这是 eax
寄存器中剩余的值。
最好查看汇编代码以获得更多说明。让我们看看函数 max(int,int)
.
的汇编代码
从gcc -S [filename].c
获得的汇编代码
max: //max() function starts here
.LFB0:
.cfi_startproc
endbr64
pushq %rbp //Stack Push
.cfi_def_cfa_offset 16 //ignore
.cfi_offset 6, -16 //ignore
movq %rsp, %rbp //ignore
.cfi_def_cfa_register 6 //ignore
movl %edi, -4(%rbp) //move int a to base pointer register from offset of 4 bytes
movl %esi, -8(%rbp) //move int b to base pointer register from offset of 8 bytes
movl -4(%rbp), %eax //move int a to extended ax register
cmpl -8(%rbp), %eax //compare b>a
jle .L2 //If cmp above succeeds execute this jle, as it checks for zero and carry flag
movl -4(%rbp), %eax //If cmp above fails start executing from this statement, int a is moved to extended ax register
jmp .L1 //jump to L1
.L2:
movl , -4(%rbp) //move number 5 to base pointer register from offset of 4 bytes
.L1:
popq %rbp //Stack Pop
.cfi_def_cfa 7, 8 //ignore
ret //Return value of extended ax register to the caller and control also.
.cfi_endproc
因为,我们可以从上面的汇编代码中得出结论,无论条件求值是什么,返回给调用者的总是扩展的 ax 寄存器(对于 x86 系统)。
这种情况下的编译器存储了第一个参数,即 a
到 eax
寄存器。
当我在 GCC 中执行以下程序时,我希望输出为 0,因为 max() 函数中缺少 return 语句,但是当我执行它时,输出为 10。什么是这种行为的原因??
#include <stdio.h>
max(int x, int y)
{
if (x > y)
return x;
else
x=5;
}
int main(void)
{
int a = 10, b = 20;
// Calling above function to find max of 'a' and 'b'
int m = max(a, b);
printf("%d", m);
}
When I execute the following program in GCC
你没有在编译器中执行某些东西! 你用 gcc 编译你的代码!
I expect output to be 0 because the return statement is missing
您的期望完全错误。 C 和 C++ 都具有“在缺少 return 语句的情况下的默认 return 值”因此,如果您的函数未定义 void
且值为让你的程序格式正确!
每个编译器都会至少给你一个警告。您应该始终使用 -Wall 或更好的 -Wextra -pedantic 进行编译。
When return type is default in function header and return statement is not provided, why is undefined behavior happening?
因为标准没有定义应该发生什么。因此,朗朗上口的术语“未定义的行为”。如果标准没有定义应该发生什么......那么实际上任何事情都可能发生,代码可以以任何方式运行。
中明确指出您的代码具有未定义的行为What is the reason for such behavior??
由于未定义行为,因此不需要编译器生成具有任何可预测行为的代码。所以它会生成一些代码,这些代码恰好起作用 as-if 该函数会返回 10,但没有人真正关心,因为它可以做它想做的事。
实用的答案来自检查生成的程序集 from the compiler (godbolt link)(编译器可以做它想做的事)。在 main
函数编译器中放置 mov DWORD PTR [rbp-4], 10
然后 mov eax, DWORD PTR [rbp-4]
然后 mov edi, eax
- 即。 edi
寄存器有 10
。然后在 max
中,编译器执行 mov DWORD PTR [rbp-4], edi
和 mov eax, DWORD PTR [rbp-4]
,然后 ret
urns 来自函数 - 当 max
returns 时,[=21= 的内容] 寄存器有 10
。因为编译器使用 mov esi, eax
来初始化 printf
的参数,printf
函数打印值 10
,这是 eax
寄存器中剩余的值。
最好查看汇编代码以获得更多说明。让我们看看函数 max(int,int)
.
的汇编代码
从gcc -S [filename].c
max: //max() function starts here
.LFB0:
.cfi_startproc
endbr64
pushq %rbp //Stack Push
.cfi_def_cfa_offset 16 //ignore
.cfi_offset 6, -16 //ignore
movq %rsp, %rbp //ignore
.cfi_def_cfa_register 6 //ignore
movl %edi, -4(%rbp) //move int a to base pointer register from offset of 4 bytes
movl %esi, -8(%rbp) //move int b to base pointer register from offset of 8 bytes
movl -4(%rbp), %eax //move int a to extended ax register
cmpl -8(%rbp), %eax //compare b>a
jle .L2 //If cmp above succeeds execute this jle, as it checks for zero and carry flag
movl -4(%rbp), %eax //If cmp above fails start executing from this statement, int a is moved to extended ax register
jmp .L1 //jump to L1
.L2:
movl , -4(%rbp) //move number 5 to base pointer register from offset of 4 bytes
.L1:
popq %rbp //Stack Pop
.cfi_def_cfa 7, 8 //ignore
ret //Return value of extended ax register to the caller and control also.
.cfi_endproc
因为,我们可以从上面的汇编代码中得出结论,无论条件求值是什么,返回给调用者的总是扩展的 ax 寄存器(对于 x86 系统)。
这种情况下的编译器存储了第一个参数,即 a
到 eax
寄存器。