【问题标题】:C: main() returning an array always equals to 56C: main() 返回一个数组总是等于 56
【发布时间】:2016-10-08 13:55:46
【问题描述】:

我想知道当我使用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 $?

即使我更改数组的大小或更改其中的数字,输出也始终为5656这个数字是什么意思?

【问题讨论】:

  • 56 没有任何意义;程序无效。
  • @JohnZwinck 我不这么认为。如果这是一个错误,那么为什么它不会改变并堆叠在 56 处?我的问题也不是在 main 上返回正确的东西(每个人都知道 0 是正确的)。
  • 您的程序无效。 56 不是一个有用的数字,它只是由于你的平台的一些怪癖而你最终得到的一些随机废话。有效类型是 int。如果您将编译器警告作为错误启用,您可能会发现您编写的代码甚至无法编译。例如我的编译器说error: return type of 'main' is not 'int'
  • @JohnZwinck 我的问题不重复。你的工作是否正确,你可能对 56 点是正确的,我不这么认为,但我的问题与任何其他问题都不重复。我请求您取消阻止我的问题...
  • 好的,我将重新打开这个问题,我们将看看它是如何进行的。顺便说一句,“做好你的工作”是惊人的。你应该试着对更多的人这么说。

标签: c shell main exitstatus


【解决方案1】:

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

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

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

超出范围的退出值可能会导致意外退出代码。一个出口 大于 255 的值返回模 256 的退出代码。例如, 退出 3809 给出的退出代码为 225 (3809 % 256 = 225)。

现在让我们通过打印变量的地址和地址modulo256来修改你的程序:

#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

如我们所见,返回状态等于6295620 % 256,正如official documentation 中所记录的那样。

【讨论】:

  • 一字节退出码不是bash的限制,而是内核的一个属性(参见execve(2)_exit(2)waitpid(2)...)。更改或修补 shell 不会更改该限制(退出代码介于 0 和 255 之间)
【解决方案2】:

根据 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:International Obfuscated C Contest 中曾出现过一次(可能不止一次)依赖此技巧的程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 2012-09-16
    • 2012-12-20
    相关资源
    最近更新 更多