Как мой код может правильно скомпилироваться без необходимых заголовков? - PullRequest
7 голосов
/ 17 мая 2010

Я использую функции fork (), exec () ...

Но как эта программа может быть скомпилирована без включения некоторых дополнительных заголовков (таких как sys / types.h, sys / wait.h).

Я использую Ubuntu 10.04 с gcc версии 4.4.3

#include <stdio.h>
#include <stdlib.h>

int main()
{
 pid_t pid;

 printf("before fork\n");

 pid = fork();

 if(pid == 0)
 {
  /*child*/
  if(execvp("./cpuid", NULL))
  {
   printf("error\n");
   exit(0);
  }
 }
 else
 {
  if(wait(NULL) != -1)
  {
   printf("ok\n");
  }
 }

 return 0;
}

Ответы [ 3 ]

12 голосов
/ 17 мая 2010

В классическом "ANSI" C, если вы вызываете функцию, не объявляя ее, компилятор ведет себя так, как если бы функция была неявно объявлена, чтобы принимать фиксированное, но неуказанное количество аргументов и возвращать int. Таким образом, ваш код действует так, как если бы fork() и execvp() были объявлены так:

int fork();
int execvp();

Поскольку execvp() принимает фиксированное количество аргументов и возвращает int, это объявление совместимо. fork() также принимает фиксированное количество аргументов, но возвращает pid_t; однако, поскольку pid_t и int являются эквивалентными типами на большинстве архитектур Linux, это объявление также эффективно совместимо.

Фактические определения этих функций находятся в стандартной библиотеке C, которая связана по умолчанию, поэтому определение доступно во время соединения, и поэтому код работает.

Как отмечает Кит Томпсон, эта языковая функция была отброшена в версии C99 стандарта языка C, и компиляторы, вызываемые в режиме C99 или C11, должны по крайней мере выдавать предупреждение при вызове функции без явного объявления.

3 голосов
/ 17 апреля 2015

ответ caf только частично правильно.

В соответствии с правилами, указанными в стандарте C89 / C90 (обычно называемом «ANSI C»), вызов функции без видимого объявления является законным. Компилятор предполагает, что функция возвращает результат int и принимает аргументы (повышенного) типа (типов), заданных в вызове. Если вызов не соответствует определению функции, поведение не определено. Для такого вызова ответственность за правильность вызова лежит исключительно на программисте; Компилятор, скорее всего, не скажет вам, если вы допустили ошибку.

Стандарт ISO C 1999 года отбросил это "неявное int" правило и сделал необъявленную функцию вызовом нарушения ограничения , требующего диагностики. (Диагностика может быть нефатальным предупреждением или может привести к сбою компиляции.) После того, как диагностика напечатана, если компилятор создает исполняемый файл, его поведение не определено.

К сожалению, многие компиляторы по-прежнему не применяют современные правила Си по умолчанию. Большинство из них можно сделать с помощью соответствующих параметров времени компиляции.

В частности, для gcc вы можете скомпилировать с помощью

gcc -std=c99 -pedantic

или

gcc -std=c11 -pedantic

(Последний еще не существовал, когда был написан ответ caf.) Или, если вы также хотите использовать специфичные для gcc расширения, вы можете использовать -std=gnu99 или -std=gnu11. По умолчанию в настоящее время -std=gnu89. Вероятно, это будет изменено на -std=gnu11 в будущем выпуске gcc.

gcc-совместимые компиляторы, такие как clang, обычно следуют тем же правилам. Что касается других компиляторов, вам придется ознакомиться с их документацией, чтобы узнать, как убедить их применять современные правила Си. (Компилятор Microsoft C имеет очень неполную поддержку стандартов позже C90.)

3 голосов
/ 17 мая 2010

exec и fork объявлены в unistd.h, который, скорее всего, включен в один файл stdio.h или stdlib.h, который вы явно указали в своем коде. "wait" происходит из sys / wait.h, хотя ... Попробуйте вызвать gcc с -c -E , чтобы сгенерировать предварительно обработанный вывод и посмотреть, откуда приходят объявления функций. 1005 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...