Хрестоматия по программированию на Си в Unix



Системные вызовы и взаимодействие с UNIX. Хрестоматия по программированию на Си в Unix - стр. 8


int f(){ return 17; } void main(){ printf("aaaa\n"); printf("bbbb\n"); f(); /* потом откомментируйте это: exit(77); */ }

Здесь функция exit вызывается неявно по окончании main, ее подставляет в программу компилятор. Дело в том, что при запуске программы exec-ом, первым начинает выполняться код так называемого "стартера", подклеенного при сборке программы из файла /lib/crt0.o. Он выглядит примерно так (в действительности он написан на ассемблере):

... // вычислить argc, настроить некоторые параметры. main(argc, argv, envp); exit();

или так (взято из проекта GNU -):

int errno = 0; char **environ; _start(int argc, int arga) { /* OS and Compiler dependent!!!! */ char **argv = (char **) &arga; char **envp = environ = argv + argc + 1; /* ... возможно еще какие-то инициализации, * наподобие setlocale( LC_ALL, "" ); в SCO UNIX */ exit (main(argc, argv, envp)); }

Где должно быть

int main(int argc, char *argv[], char *envp[]){ ... return 0; /* вместо exit(0); */ }

Адрес функции _start() помечается в одном из полей заголовка файла формата a.out как адрес, на который система должна передать управление после загрузки программы в память (точка входа).

Какой код ответа попадет в exit() в этих примерах (если отсутствует явный вызов exit или return) - непредсказуемо. На IBM PC в вышенаписанном примере этот код равен 17, то есть значению, возвращенному последней вызывавшейся функцией. Однако это не какое-то специальное соглашение, а случайный эффект (так уж устроен код, создаваемый этим компилятором).

6.5.6. Процесс-отец может дождаться окончания своего потомка. Это делается системным вызовом wait и нужно по следующей причине: пусть отец - это интерпретатор команд. Если он запустил процесс и продолжил свою работу, то оба процесса будут предпринимать попытки читать ввод с клавиатуры терминала - интерпретатор ждет команд, а запущенная программа ждет данных. Кому из них будет поступать набираемый нами текст - непредсказуемо! Вывод: интерпретатор команд должен "заснуть" на то время, пока работает порожденный им процесс:

int pid; unsigned short status; ... if((pid = fork()) == 0 ){ /* порожденный процесс */ ... // перенаправления ввода-вывода. ... // настройка сигналов. exec(....); perror("exec не удался"); exit(1); } /* иначе это породивший процесс */ while((pid = wait(&status)) > 0 ) printf("Окончился сын pid=%d с кодом %d\n", pid, status >> 8); printf( "Больше нет сыновей\n");




Содержание  Назад  Вперед