Странное поведение WEXITSTATUS с `G++ 4.9.4`
Этот фрагмент кода ниже компилируется,
#include<sys/types.h>
#include<sys/wait.h>
#include<iostream>
int main()
{
int ret = 0xFFFF;
std::cout << WEXITSTATUS(ret);
}
тогда как этот фрагмент кода действительно не компилируется с
G++ 4.9.4
:
#include<sys/types.h>
#include<sys/wait.h>
#include<iostream>
int main()
{
std::cout << WEXITSTATUS(0xFFFF);
}
Вот на что жалуется компилятор:
In file included from /usr/include/x86_64-linux-gnu/sys/wait.h:77:0,
from t.cpp:2:
t.cpp: In function ‘int main()’:
t.cpp:7:22: error: lvalue required as unary ‘&’ operand
std::cout << WEXITSTATUS(0xFFFF);
^
Вот подробная информация о компиляторе:
g++ --version
g++ (Ubuntu 4.9.4-2ubuntu1~16.04) 4.9.4
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
И компилятор устанавливается на Ubuntu16.04 командами ниже
sudo apt-get install gcc-4.9
sudo apt-get install g++-4.9
sudo update-alterntives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 20
sudo update-alterntives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 20
Примечание: я должен использовать g++-4.9, у меня нет другого выбора.
И Странно, что я не смог воспроизвести указанное явление на
godbolt.org
. Он компилируется на godbolt.org с
gcc 4.9.3
(
gcc 4.9.4
не доступен).
Вот результат
g++ -E the_said_code_snippet_does_not_compile.cpp
//omit
# 4 "t.cpp" 2
int main()
{
std::cout << ((((*(const int *) &(0xFFFF))) & 0xff00) >> 8);
}
Может ли кто-нибудь пролить свет на этот вопрос?
ОБНОВЛЕНО:
Теперь я могу воспроизвести ошибку! Смотрите эту ссылку.
ОБНОВЛЕНО:
Это просто упрощенный пример. С чем я на самом деле сталкиваюсь
WEXITSTATUS(pclose(fp))
не компилируется.
1 ответ
Макрос — это вопрос реализации стандартной библиотеки C, а не компилятора как такового. Обычно (и в случае с GCC) компилятор не предоставляет реализацию стандартной библиотеки C. Это независимый пакет.
Большинство дистрибутивов Linux, включая Ubuntu, используют glibc в качестве реализации стандартной библиотеки C.
В glibc до версии 2.23 включительно макрос определялся следующим образом при использовании C++ и__USE_MISC
установлен (см. ссылку фиксации ниже):
# define __WAIT_INT(status) (*(const int *) &(status))
// ...
# define WEXITSTATUS(status) __WEXITSTATUS (__WAIT_INT (status))
Реальная реализация макроса находится внутри
__WEXITSTATUS
, но использование
__WAIT_INT
кажется, с целью поддержки не-POSIX варианта
" union wait "wait
интерфейс. С этим определением prvalue нельзя использовать с макросом, потому что он пытается получить адрес
status
.
В 2016 году с коммитом b49ab5f4503f36dcbf43f821f817da66b2931fe6 поддержка union wait — согласно
NEWS
запись устарела в начале 1990-х - была удалена, и теперь определение просто
# define WEXITSTATUS(status) __WEXITSTATUS (status)
Теперь это будет работать и с prvalue.
Похоже, что Ubuntu 16.04 по-прежнему использует версию glibc до этого изменения, что неудивительно, поскольку она была выпущена во время коммита.
Я не знаю, что POSIX говорит о том, можно ли использовать макрос с
int
rvalue, а не имя переменной.
Что
WEXITSTATUS
не всегда может использоваться непосредственно при вызове
pclose
кажется известная проблема. По-видимому, вышеупомянутое расширение, которого больше нет в glibc, присутствовало (присутствует ли?) также в (некоторых?) BSD (и может происходить от них?). См., например , этот вопрос, ответ на который также выражает сомнения в соответствии с POSIX. Однако OpenBSD, упомянутая в связанном вопросе, также удалила ожидание союза в 2014 году. Согласно журналу изменений, она устарела с 4.3BSD (выпущенной в 1986 году).