2010-09-01 2 views
3

Я удивлен, почему это работает?C угловой корпус и ловушка

short main [] ={}; 

Это единственное содержимое в файле. Он правильно компилируется на gcc. Но когда я запускаю, он печатает ошибку сегментации. Когда я переименовываю main, компилятор дает ошибки. Может ли кто-нибудь объяснить мне, что здесь происходит.

+0

Я уверен, что видел этот уже, вы объявляете внешний символ основного и компоновщик Безразлично Не заботьтесь о типе. Это неверно. C. – jbcreix

+1

-1 на вопрос спрашивает, почему какой-то смешной код с неопределенным поведением «работает» (в очень извращенном смысле хуже, не меньше). –

+2

Я полагаю, кто-то должен упомянуть об этом [запись IOCCC] (http://www.ioccc.org/years.html#1984_mullender). –

ответ

4

По-видимому, компоновщик не знает тип глобальных объектов (например: переменная или функция), а только адрес; поэтому он связывает программу, как будто ваша переменная была функцией. Что происходит по очевидным причинам.

1

Попробуйте выполнить компиляцию с большим количеством опций. :)

Например, добавив простой -Wall

gcc -Wall test.c -o t 
test.c:1: warning: ‘main’ is usually a function 

Я не читал соответствующую стандартную страницу, но, видимо, вы просто должны иметь основной какой-то для того, чтобы компилировать, не обязательно функцию .. .

+0

'gcc -ansi -pedantic -W -Wall' –

3

Вы получаете ошибку?

Undefined symbols: 
    "_main", referenced from: 
     start in crt1.10.6.o 
ld: symbol(s) not found 
collect2: ld returned 1 exit status 

Это не ошибка компилятора, а ошибка компоновщика.

В компиляции каждый исходный файл переводится в файл объекта.

Нет никакой проверки, существует ли int main(), потому что программа может состоять из нескольких источников, а main() определяется только в одном из них, или ее даже не нужно существовать (например, в динамической библиотеке). Поскольку источник

short main[] = {}; 

считается действительной декларацией (создать глобальный short массив с именем main и инициализировать пустой массив) компилятором, он не будет создавать какие-либо ошибок.

Обнаруживается, существует ли проверка наличия int main(). Компонент связывает скомпилированные объектные файлы с исполняемым исполняемым файлом. Если линкер не может найти символ main, он будет жаловаться, как тот, который я описал выше. К сожалению, обычный C ABI не различает функции или виды экспортируемых переменных. Так что даже если main объявлен как массив, так как компоновщик знает только «что-то под названием main существует» и не может проверить больше, он пройдет так же хорошо.

В результате программа генерируется без ошибок, хотя она ошибочно написана.

Когда программа запущена, так называемый main не содержит исполняемый код. Скорее всего, это всего лишь некоторые данные (вероятно, обнулены). Таким образом, система может сделать что-нибудь неожиданное (в вашем случае это SEGFAULT).

Это на самом деле может быть пойман при компиляции с -Wall флагом ССАГПЗ, что дает предупреждение:

<stdin>:1: warning: ‘main’ is usually a function 
+0

Хорошо, я понял, но в моем сознании возникает еще один вопрос, можем ли мы написать что-то в этом массиве, которое будет делать что-то полезное, например, печатать привет. Есть опция gcc fwritablestrings, что она будет делать? –

+0

short main [] = {}; Я не думаю, что это действительная декларация. нулевой инициализатор? возможно, действительный C99? – Nyan

+0

@Nyan: Возможно расширение GCC. Во всяком случае, это не главное. – kennytm