我想知道当我使用main
函数的返回值时会发生什么。
我发现如果我从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
是什么意思?
程序返回一个指针。它不是一个"数组",因为你把它放在问题中。因为数组的名称计算结果为其第一项的地址(与数组本身的地址相同)。
在C语言中,从main
函数返回的值被解释为退出状态,即在您的示例中使用的$?
变量。
我猜,你正在运行Bash shell,因为在Bash中退出状态存储在$?
变量中。指针通常是一个大数字,至少大于255,这是Bash中的最大退出码:
超出范围的退出值可能导致意外的退出代码。退出大于255的值返回以256为模的退出码。例如,出口3809给出的出口代码为225(3809 % 256 = 225)。
现在让我们通过打印变量的地址和地址模256:
来修改程序#include <stdio.h>
int main(void) {
static int x[3];
printf("%ld ==> %dn", (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
我们可以看到,返回状态等于6295620 % 256
,正如官方文档中所记录的那样。
根据ISO C, int* main(void)
不是需要实现支持的启动函数main
的形式之一。因此,该行为不是由语言标准定义的。
int *main(void)
可以作为C实现提供的文档扩展。通过这种方式,C实现可以支持编写启动函数的其他方式。
更有可能的是,构造是错误的,你的实现只是忽略了这种情况;它只是编译代码,让机器指令做它们可能做的事情。要理解实际的行为,你必须理解在那个层次上发生了什么。
很可能,返回的指针本身的按位表示形式被解释为整数终止状态值,转换为操作系统退出码56。(可能值中的某些位域,例如最低的8位,是56)。这是假设int *
和int
以相同的方式从函数返回。他们可能不会。例如,在摩托罗拉68000系列处理器的C编译器中,存在通过A0寄存器返回指针和D0中的整数值的惯例。因此,如果编写int *
返回函数以满足对期望返回int
的东西的外部引用,则调用者将接收碰巧在D0中的任何垃圾,而指针已经进入A0。
因为行为没有定义,所以不需要诊断!在C语言中,您甚至可以这样写:
int main[42] = { 3 };
在某些环境中将编译和链接。当执行时,数组数据最终用作机器语言函数映像。在IOCC:国际混淆C竞赛中,一个依赖于这个技巧的程序出现过一次(也许不止一次)。