C中的Implict函数声明是否实际生成了对象代码?

Rob*_*nes 1 c compiler-construction

在讨论中关于转换malloc许多人的返回值已声称隐式声明malloc会导致返回值被转换为int然后重新转换回T*可能导致在以下情况下截断指针:

sizeof(int) < sizeof(void*)
Run Code Online (Sandbox Code Playgroud)

这意味着编译器会执行以下操作:

  1. 链接并调用正确的目标代码定义 malloc
  2. 生成目标代码以将返回值转换为较短的int类型
  3. 生成目标代码以转换回更大的目标指针类型

有人真的可以证明这发生了吗?在64位Linux上使用一些示例代码说?

我自己做,但我无法访问64位机器.

Mar*_*sey 6

描述发生的事情的问题在步骤2中.使用隐式声明,调用站点的代码实际上不会"转换"函数的返回值.

会发生的是,调用站点的代码通过假设它的类型为"int"来提取返回值(通常来自寄存器或堆栈外).对于不同的操作系统和编译器,执行此操作的过程是不同的,并且通常由ABI文档指定.

对于最常见的ABI,int和void*的返回位置和大小是相同的,所以即使它不正确,你实际上也不会有任何问题.对于32位和64位平台上的Linux,Windows和Mac OS X 都是如此,我相信 32位平台.

在64位平台上,"long"和"void*"更常见的是相同的大小,因此如果你有一个malloc()的隐式声明,返回值将被截断.但是,有几种流行的64位编程模型.

回到DOS开发的"美好时光",可以创建以"int"为16位,指针为32位(实际为24位)的模式运行的程序.在这些情况下,使用隐式原型调用malloc()会截断返回的值.

请注意,即使在截断返回值的情况下,您仍可能没有运行时问题,具体取决于该值是否实际超出int的有效范围.


在Mac OS X上,在64位模式下,此代码:

#include <stdio.h>

int main (int argc, const char * argv[]) {
    int x = malloc(128);
    void *p = malloc(128);
    printf("Hello, World!\nsizeof(int)=%d,sizeof(void*)=%d,x=0x%xd,p=%p\n", sizeof(int), sizeof(void *), x, p);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

打印:

你好,世界!的sizeof(INT)= 4,的sizeof(无效*)= 8,X = 0x1001c0d,P = 0x100100240

请注意,"x"值的位数少于"p"值,而是静默地删除了值的最高32位.两次调用malloc时的实际汇编代码如下所示:

LM2:
    movl    $128, %edi
    call    _malloc
    movl    %eax, -12(%rbp)
LM3:
    movl    $128, %edi
    call    _malloc
    movq    %rax, -8(%rbp)
Run Code Online (Sandbox Code Playgroud)

因此,malloc(在%rax中)返回了正确的值,但是当movl指令被移动到变量"x"时,它会截断它.