繁体   English   中英

为什么这个function在没有return语句的情况下返回数组的大小?

[英]Why does this function returns size of array when there is no return statement?

对于这个程序,我得到 output 作为 8。 为什么这个 function 在没有 return 语句的情况下返回数组的大小? 当我写返回语句时它工作正常,但我仍然很好奇为什么这个 function 返回数组的大小。 我认为它应该返回垃圾值。

#include <stdio.h>
int sumofelements(int A[],int size)
{
    int i,sum=0;
    for(i=0;i<size;i++) 
        sum = sum + A[i];
}

int main()
{
    int A[]={3,4,5,6,3,6,1,10};
    int size=sizeof(A)/sizeof(A[0]);
    int total=sumofelements(A,size);
    printf("sum of the elements=%d",total);
}

行为未定义。 任何值都是可能的,包括观察到的行为。 在一些奇特的架构上,陷阱值可能会导致其他奇怪的行为。

对于您的特定情况, main期望sumofelements放置其返回值(某些 CPU 寄存器)的位置恰好包含size的值,但不能保证:它可能不在不同的 CPU/OS/编译器组合上/一组选项/一天中的时间...

使用gcc -Wall -Werror或类似的警告级别来避免此类愚蠢的错误。

您可以在Godbolt 的编译器资源管理器上查看程序集和行为,并使用编译器标志和编译器版本来了解行为的易变性。 使用-O2gccclang 都为 sumofelements生成一个简单的ret指令,甚至不为sumofelements调用调用这个printf

未明确从非空 function( main()除外)返回值会导致未定义的行为 这意味着任何事情都可能发生:崩溃、返回垃圾值,或者更糟糕的是,返回预期值!

您应该始终从非空 function 返回一些(有意义的)东西。

返回值是从eax中选取的,它是你 CPU 上的一个寄存器(寄存器就像你的 CPU 自己在 RAM 之外存储一些少量数据的地方)它恰好是 function 结束之前eax包含数组的大小。

可能在i < size中, size存储在eax中,并且在您的 function 结束之前不会进一步修改,但是您必须objdump -d您的程序并将其粘贴到此处,以便我说出任何确定的内容。

如果您想了解更多信息,请输入“CPU registers”并在线阅读一些内容。

为了这样做,我将扩展我的答案。

好的,我复制了你的代码并使用 GCC MinGW 编译它并使用 objdump 反汇编它。 现在这里是反汇编:

<sumofelements>:
0000000000000000 <sumofelements>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   48 89 7d e8             mov    QWORD PTR [rbp-0x18],rdi
   8:   89 75 e4                mov    DWORD PTR [rbp-0x1c],esi
   b:   c7 45 f8 00 00 00 00    mov    DWORD PTR [rbp-0x8],0x0
  12:   c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  19:   eb 1d                   jmp    38 <sumofelements+0x38>
  1b:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  1e:   48 98                   cdqe
  20:   48 8d 14 85 00 00 00    lea    rdx,[rax*4+0x0]
  27:   00
  28:   48 8b 45 e8             mov    rax,QWORD PTR [rbp-0x18]
  2c:   48 01 d0                add    rax,rdx
  2f:   8b 00                   mov    eax,DWORD PTR [rax]
  31:   01 45 f8                add    DWORD PTR [rbp-0x8],eax
  34:   83 45 fc 01             add    DWORD PTR [rbp-0x4],0x1
  38:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  3b:   3b 45 e4                cmp    eax,DWORD PTR [rbp-0x1c]
  3e:   7c db                   jl     1b <sumofelements+0x1b>
  40:   90                      nop
  41:   5d                      pop    rbp
  42:   c3                      ret

如果你检查反汇编,你可以看到eax的最后修改是在第 38 个字节,之后循环结束,我们返回。 特别是这条线

mov    eax,DWORD PTR [rbp-0x4]

是循环检查i < size之前的行。 该行将[rbp-0x4]移动到eax 如果我们 go 回到程序的开头,我们可以看到[rbp-0x4]i

考虑到所有这些,一切都是有道理的。 要使循环结束, i < size必须解析为false 由于size为 8,因此i也必须为 8 才能结束循环。 i的值被移入eax以检查它是否小于size并且在循环结束的迭代中i的值将是 8,因此eax也将是 8。循环结束并且我们返回 eax 中的内容。 所以事实上它并不像我最初猜测的那样是eax的大小,而是i

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM