2016-10-08 12 views
0

Интересно, что происходит, когда я играю с возвращаемым значением функции main.C: main() возврат массива всегда равен 56

Я обнаружил, что если я вернусь переменную массива от main (которая должна быть статусом выхода) и распечатать статус выхода в оболочке, выход всегда будет 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?

+4

56 ничего не значит; программа недействительна. –

+1

@JohnZwinck Я так не думаю. Если это была ошибка, то почему она не изменится и стек на 56? Также моя проблема заключается в том, чтобы вернуть правильную вещь в главном (все знают 0 правильно). –

+1

Ваша программа недействительна. 56 - не полезное число, это всего лишь случайное дерьмо, в котором вы оказались из-за некоторой причуды вашей платформы. Допустимый тип - int. Если вы включите предупреждения компилятора как ошибки, вы можете обнаружить, что ваш код в письменном виде даже не будет компилироваться. Например, мой компилятор говорит 'error: return type of 'main' is not 'int'' –

ответ

5

Ваша программа возвращает указатель. Это не «массив», как вы выразились в этом вопросе. Поскольку имя массива оценивается по адресу его первого элемента (который совпадает с адресом самого массива).

В C значение, возвращаемое функцией main, интерпретируется как exit status, то есть переменная $?, используемая в вашем примере.

Я думаю, вы используете оболочку Bash, так как в Bash статус выхода сохраняется в переменной $?. Указатель, как правило, большое количество, по крайней мере больше, чем , который является максимальным 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 :

#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.

+1

Один байтовый код выхода не является ограничением 'bash', а является свойством ядра (см. [Execve (2)] (http://man7.org/linux/man-pages/man2/execve.2.html), [_exit (2)] (http://man7.org/linux/man-pages/man2/exit.2 .html), [waitpid (2)] (http://man7.org/linux/man-pages/man2/waitpid.2.html) ...). Изменение или исправление оболочки не изменит этот предел (коды выхода находятся между 0 и 255) –

2

В соответствии с ISO C int* main(void) не является одной из форм функции запуска main, которая необходима для поддержки. Таким образом, поведение не определяется стандартом языка.

int *main(void) может работать как документированное расширение, обеспечиваемое вашей реализацией C. Таким образом, реализации C могут поддерживать дополнительные способы записи функции запуска.

Скорее всего, конструкция ошибочна, и ваша реализация просто игнорирует ситуацию; он просто компилирует код и позволяет машинным инструкциям делать то, что они могут. Чтобы понять реальное поведение, вы должны понимать, что происходит на этом уровне.

Вполне возможно, побитовое представление возвращаемого самого указателя интерпретируются как значение состояния завершения целого числа, которое переводит к операционной системе коду выхода 56. (возможно, некоторым битовому поле в значении, такие как самые низкие 8 бит, составляет 56).Это предполагает, что int * и int возвращаются из функции таким же образом. Они могут и не быть. Например, в компиляторах C для процессоров серии Motorola 68000 существует соглашение о возврате указателя через регистр A0 и целочисленное значение в D0. Поэтому, если функция возврата int * записывается, чтобы удовлетворить внешнюю ссылку на то, что, как ожидается, будет возвращено int, вызывающий абонент получает любой мусор, находящийся в D0, тогда как указатель переместился в A0.

Поскольку поведение не определено, нет необходимости в диагностике! На языке C вы можете даже написать это:

int main[42] = { 3 }; 

В некоторых средах, которые будут скомпилированы и ссылки. При выполнении данные массива заканчиваются использованием изображения функции машинного языка. Программа, основанная на этом трюке один раз (возможно, более одного раза), появилась на Международном конкурсе «Обфускация C» IOCC.