当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?

因为标准没有定义应该发生什么。因此,朗朗上口的术语“未定义的行为”。如果标准没有定义应该发生什么......那么实际上任何事情都可能发生,代码可以以任何方式运行。

the standard C11 6.9.1p12.

中明确指出您的代码具有未定义的行为

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], edimov eax, DWORD PTR [rbp-4],然后 returns 来自函数 - 当 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 系统)。
这种情况下的编译器存储了第一个参数,即 aeax 寄存器。