В C главное не должно быть функцией? - PullRequest
13 голосов
/ 12 февраля 2010

Этот код компилируется, но без сюрпризов, он не работает во время компоновки (основной не найдено):

Листинг 1:

void main();

Ошибка ссылки: \ mingw \ lib \ libmingw32.a (main.o): main.c :(. Text + 0x106) неопределенная ссылка на _WinMain @ 16 '

Но код ниже компилируется и связывается нормально, с предупреждением:

Листинг 2:

void (*main)();

предупреждение: 'main' обычно является функцией

Вопросы:

  1. В листинге 1 компоновщик должен иметь жаловался на отсутствие "основного". Зачем он ищет _WinMain @ 16?

  2. Исполняемый файл, сгенерированный из листинг 2 просто вылетает. Что такое причина?

Спасибо за ваше время.

Ответы [ 8 ]

30 голосов
/ 12 февраля 2010

Правда, main не обязательно должно быть функцией. Это использовалось в некоторых запутанных программах, которые содержат двоичный программный код в массиве с именем main.

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

6 голосов
/ 12 февраля 2010

В большинстве систем компиляции Си нет информации о типе, связанной с символами, которые связаны. Вы можете объявить основной как, например ::100100

char main[10];

и компоновщик был бы совершенно счастлив. Как вы заметили, программа, вероятно, вылетит, если вы умело не инициализируете содержимое массива.

Ваш первый пример не определяет main, он просто объявляет его, следовательно, ошибка компоновщика.

Второй пример определяет main, но неверно.

4 голосов
/ 12 февраля 2010

Случай 1. специфичен для Windows - компилятор, вероятно, генерирует символ _WinMain, когда main определен правильно.

Случай 2. - у вас есть указатель, но в качестве статической переменной он инициализируется нулем , таким образом, сбой.

3 голосов
/ 12 февраля 2010

На платформах Windows основным модулем программы является WinMain, если вы не настроили программу как консольное приложение. «@ 16» означает, что он ожидает 16 байтов параметров. Так что компоновщик будет очень доволен вами, если вы предоставите ему функцию с именем WinMain с 16 байтами параметров.

Если вы хотели консольное приложение, это означает, что вы что-то напутали.

2 голосов
/ 12 февраля 2010

Вы объявили указатель на функцию с именем main, и компоновщик предупредил вас, что это не сработает.

Сообщение _WinMain связано с работой программ Windows. Ниже уровня среды выполнения C исполняемый файл Windows имеет WinMain.

1 голос
/ 12 февраля 2010

Попробуйте переопределить его как int main(int argc, char *argv[])

У вас есть ошибка компоновщика. Компоновщик ожидает найти функцию с этой «подписью», а не без параметров

См. http://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html и т. Д.

0 голосов
/ 12 февраля 2010

1.) Зависимая функция (компилятор / платформа) вызывается перед выполнением кода в main и, следовательно, вашего поведения (_init в случае linux / glibc).
2) Сбой кода во 2-м случае оправдан, так как система не может получить доступ к содержимому символа main как функции, которая фактически является указателем на функцию, указывающую на произвольное местоположение.

0 голосов
/ 12 февраля 2010

В листинге 1 вы говорите: «В моем коде есть определение main (), я обещаю!». Вот почему он компилируется. Но вы там лежите, поэтому ссылка не работает. Причина, по которой вы получаете отсутствующую ошибку WinMain16, заключается в том, что стандартные библиотеки (для компилятора Microsoft) содержат определение main (), которое вызывает WinMain (). В программе Win32 вы должны определить WinMain (), а компоновщик будет использовать библиотечную версию main () для вызова WinMain ().

В листинге 2 у вас есть определенный символ, называемый main, поэтому и компилятор, и компоновщик довольны, но код запуска попытается вызвать функцию, находящуюся в местоположении "main", и обнаружит, что на самом деле функции нет там и вылетает.

...