Есть ли польза в использовании макроса WEXITSTATUS в C по сравнению с делением на 256 при выходе ()? - PullRequest
12 голосов
/ 30 апреля 2009

Я делал упражнение для университета, где мне приходилось возвращать значение с выходом, это значение было подсчетом чего-то. Это может быть больше 255 (которое exit () не может обработать), но учитель предложил использовать тестовые данные, когда количество никогда не может превышать это значение.

После всего этого мне нужно было обработать это значение счетчика, состояние выхода, я получил это значение в основном процессе с помощью waitpid (). К моему удивлению, если дочерний процесс возвратил 1, «реальное» значение в основном процессе было 256, 2 было 512 и так далее ...

Мне нужно было напечатать это значение, поэтому я просто разделил его на 256, и это было сделано. Однако, если я использую макрос WEXITSTATUS (), я также получу это значение так, как я хочу ...

Я посмотрел на исходный код C, и вот что я узнал:

#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)

Я понимаю, что здесь происходит, например, 512 в двоичном виде - это 10 0000 0000, сдвиг на 8 o вправо даст 00 0000 0010, то есть 2 в десятичном виде. Что я не понимаю в этом макросе, так это оператор & и тот факт, что 0xff00 кажется случайным числом (хотя, вероятно, это не так, откуда оно?). Что именно это делает, почему в макросе есть «& 0xff00»? Разве это не сработает?

И настоящий вопрос в этой теме, это то же самое, что называть этот макрос в моем коде делением на 256?

Ответы [ 4 ]

18 голосов
/ 01 мая 2009

И настоящий вопрос в этой теме, это то же самое, чтобы назвать этот макрос в моем коде как деление на 256?

Вероятно, он всегда будет работать в тех случаях, когда дочерний процесс завершается нормально (т. Е. Путем вызова exit (), а не из-за ошибки сегментации, ошибки подтверждения и т.

Состояние, сохраняемое waitpid(), кодирует как причину завершения дочернего процесса, так и код завершения. Причина сохраняется в младшем значащем байте (полученном status & 0xff), а код выхода сохраняется в следующем байте (маскируется status & 0xff00 и извлекается WEXITSTATUS()). Когда процесс завершается нормально, причина равна 0, поэтому WEXITSTATUS эквивалентно сдвигу на 8 (или делению на 256). Однако, если процесс прерывается сигналом (например, SIGSEGV), код выхода отсутствует, и вы должны использовать WTERMSIG, чтобы извлечь номер сигнала из байта причины.

3 голосов
/ 04 февраля 2012

Насколько я могу судить по проверке Single Unix Spec, ваша система хранит состояние выхода в крайнем втором октете, но я не верю стандарту делает. Итак, вы должны использовать макросы как минимум по нескольким причинам:

  • Они правы. Сдвиг битов отрицательного числа делает разные вещи на разных платформах. Это работает так, как вы хотите на вашем? Я не знаю.
  • Они простые. Сразу понятно, что делает WEXITSTATUS. Менее так с другими подходами. Если бы вы увидели раскрученную вручную версию WIFSIGNALED, вы бы ее узнали? Сколько времени это займет, чем WIFSIGNALED.
  • Они портативные. Так как спецификация говорит, что это делает, она будет работать на каждой системе (по крайней мере, почти на каждой Unix-подобной системе).
3 голосов
/ 01 мая 2009

Если переменная состояния представляет собой 16-разрядное целое число со знаком («короткое») на машине, где «int» - это 32-разрядное значение, и если состояние выхода находится в диапазоне 128..255, то WEXITSTATUS () по-прежнему дает правильное значение, тогда как деление на 256 или простое смещение вправо приведут к неверному значению.

Это связано с тем, что сокращение будет расширяться до 32-разрядного знака, а маскирование отменяет расширение знака, оставляя в результате правильное (положительное) значение.

Если машина использует 16-битные целые числа, то код в WEXITSTATUS (), вероятно, будет выполнять сдвиг, а затем маскировать для обеспечения аналогичного поведения:

#define WEXITSTATUS(status) (((status)>>8) & 0xFF)

Именно потому, что реализация заботится о таких деталях, вам следует использовать макрос WEXITSTATUS ().

2 голосов
/ 30 апреля 2009

Здесь 0xff00 - двоичная маска ( текст ссылки ). ANDing со значением устанавливает все биты на ноль, кроме второго байта (считая справа).

Вы должны использовать WEXITSTATUS только для процесса, который, как известно, завершился нормально. Эта информация предоставляется макросом WIFEXITED.

И настоящий вопрос в этой теме, это то же самое, что называть этот макрос в моем коде делением на 256?

Макрос делает код более читабельным, и он гарантированно работает в любой реализации, совместимой с Posix. Насколько я знаю, Posix не определяет формат статуса, поэтому вы не можете ожидать, что ваш код будет работать везде.

...