Странное поведение 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 говорит о том, можно ли использовать макрос с intrvalue, а не имя переменной.

Что WEXITSTATUSне всегда может использоваться непосредственно при вызове pcloseкажется известная проблема. По-видимому, вышеупомянутое расширение, которого больше нет в glibc, присутствовало (присутствует ли?) также в (некоторых?) BSD (и может происходить от них?). См., например , этот вопрос, ответ на который также выражает сомнения в соответствии с POSIX. Однако OpenBSD, упомянутая в связанном вопросе, также удалила ожидание союза в 2014 году. Согласно журналу изменений, она устарела с 4.3BSD (выпущенной в 1986 году).

Другие вопросы по тегам