Есть ли какая-либо выгода в использовании макроса WEXITSTATUS в C по сравнению с делением на 256 при статусе exit()?

StackOverflow https://stackoverflow.com/questions/808541

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top