C: main() 返回一个数组总是等于 56

C: main() returning an array always equals to 56

我想知道当我使用 main 函数的 return 值时会发生什么。

我发现如果我 return 来自 main 的数组变量(应该是退出状态)并在 shell 中打印退出状态,输出总是56.我不知道为什么?

C程序:

int* main(void) {
    static int x[3];
    x[0]=89;
    x[1]=15;
    x[2]=10;
    return x;
} 

我测试如下:

gcc array_return.c -o array_return
./array_return
echo $?

输出总是56,即使我改变了数组的大小,或者改变了其中的数字。数字 56 是什么意思?

您的程序return是一个指针。这不是您在问题中提出的 "array" 。因为数组的名称计算为其第一项的地址(与数组本身的地址相同)。

在 C 语言中,从 main 函数中 return 的值被解释为 exit status,即您的示例中使用的 $? 变量。

我猜,你是 运行 Bash shell,因为在 Bash 中,退出状态存储在 $? 变量中。指针通常是一个大数,至少大于255,也就是最大值exit code in Bash:

Out of range exit values can result in unexpected exit codes. An exit value greater than 255 returns an exit code modulo 256. For example, exit 3809 gives an exit code of 225 (3809 % 256 = 225).

现在让我们通过打印变量的地址和地址 modulo 256:

来修改您的程序
#include <stdio.h>

int main(void) {
    static int x[3];
    printf("%ld ==> %d\n", (size_t)x, (size_t)x % 256);
    return (int)x;
}

让我们编译它并测试我是否正确:

$ gcc -Wall -g test.c -o test && ./test; echo $?
test.c: In function ‘main’:
test.c:6:12: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     return (int)x;
            ^
6295620 ==> 68
68

如我们所见,return 状态等于 6295620 % 256,如 official documentation.

中所述

根据 ISO C,int* main(void) 不是需要实现支持的启动函数 main 的形式之一。所以行为没有被语言标准定义。

int *main(void) 可以作为您的 C 实现提供的文档扩展。以这种方式,C 实现可以支持编写启动函数的其他方式。

更可能的是,构造是错误的,您的实现只是忽略了这种情况;它只是编译代码并让机器指令执行它们可能执行的操作。要了解实际行为,您必须了解该级别发生的情况。

很有可能,returned 指针本身 的按位表示被解释为整数终止状态值,转换为操作系统退出代码 56 .(可能值中的某些位域,例如最低8位,是56)。这是假设 int *int 以相同的方式从函数中 returned。他们可能不是。例如,在摩托罗拉 68000 系列处理器的 C 编译器中,存在一个指针通过 A0 寄存器 return 编辑的约定,以及 D0 中的一个整数值。因此,如果编写 int * returning 函数来满足对预期 return int 的内容的外部引用,则调用者会收到 D0 中恰好存在的任何垃圾,而指针已经进入A0.

由于未定义行为,因此不需要进行诊断!在C语言中,你甚至可以这样写:

int main[42] = { 3 };

在某些会编译的环境中,link。执行时,数组数据最终用作机器语言函数图像。一个依赖这个技巧的程序曾经(也许不止一次)出现在 IOCC: International Obfuscated C Contest.