关于 WEXITSTATUS 与 `G++ 4.9.4` 的奇怪行为
Strange behavior about WEXITSTATUS with `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
上重现上述现象。它 compiles on 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);
}
有人能解释一下这件事吗?
已更新:
我现在可以重现错误了!看这个link。
已更新:
这只是一个简化的例子。我实际上面对的是 WEXITSTATUS(pclose(fp))
不编译。
这看起来像是宏的古怪实现,导致运算符优先级出现问题。通常它应该是这样的:
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
现在如果是(结果完全错误)
#define WEXITSTATUS(status) status & 0xff00 >> 8
您将获得以下订单:
( std::cout << status ) & (0xff00 >> 8)
虽然我无法想象会存在这种破烂的实现?
经过处理的代码片段显示,宏假设 status
是一个至少返回纯右值的表达式,人们可以获得它的地址和将其转换为 const int
的“魔法”。
#define WEXITSTATUS(status) ((((*(const int *) &(status))) & 0xff00) >> 8)
错误是由于地址运算符得到了错误的操作数。本质上,这个宏不能仅与表达式或变量一起使用常量,假设这些是从文档中描述的特定源返回的值。
WEXITSTATUS
宏是 C 标准库实现的问题,而不是编译器本身的问题。通常(在 GCC 的情况下)编译器不提供 C 标准库实现。是独立包。
大多数 Linux 发行版,包括 Ubuntu,使用 glibc 作为 C 标准库实现。
在 glibc 直到版本 2.23(含)中,当使用 C++ 时,宏是按以下方式定义的,并且设置了 __USE_MISC
(参见下面的提交 link):
# define __WAIT_INT(status) (*(const int *) &(status))
// ...
# define WEXITSTATUS(status) __WEXITSTATUS (__WAIT_INT (status))
宏的实际实现在__WEXITSTATUS
里面,但是使用__WAIT_INT
好像是为了支持non-POSIX》union等待" wait
界面的变体。使用此定义,纯右值不能与宏一起使用,因为它试图获取 status
.
的地址
2016 年,commit b49ab5f4503f36dcbf43f821f817da66b2931fe6 支持 union wait - 根据 1990 年代初期弃用的 NEWS
条目 - 已被删除,现在定义很简单
# define WEXITSTATUS(status) __WEXITSTATUS (status)
现在它也适用于纯右值。
似乎 Ubuntu 16.04 仍然使用该更改之前的 glibc 版本,这并不奇怪,因为它是在提交时发布的。
我不知道 POSIX 关于是否可以使用带有 int
右值而不是变量名的宏的说法。
WEXITSTATUS
不能总是直接用于对 pclose
的调用似乎是已知问题。显然,现在 glibc 中不再存在的 above-mentioned 扩展曾经(是?)也存在于(某些?)BSD 中(并且可能源自它们?)。参见例如this question, in which the answer also expresses doubts about POSIX-compliance. However, OpenBSD, mentioned in the linked question, also removed union wait in 2014. According to the changelog 自 4.3BSD(1986 年发布)以来,它已被弃用。
下面的代码片段可以编译,
#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
上重现上述现象。它 compiles on 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);
}
有人能解释一下这件事吗?
已更新:
我现在可以重现错误了!看这个link。
已更新:
这只是一个简化的例子。我实际上面对的是 WEXITSTATUS(pclose(fp))
不编译。
这看起来像是宏的古怪实现,导致运算符优先级出现问题。通常它应该是这样的:
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
现在如果是(结果完全错误)
#define WEXITSTATUS(status) status & 0xff00 >> 8
您将获得以下订单:
( std::cout << status ) & (0xff00 >> 8)
虽然我无法想象会存在这种破烂的实现?
经过处理的代码片段显示,宏假设 status
是一个至少返回纯右值的表达式,人们可以获得它的地址和将其转换为 const int
的“魔法”。
#define WEXITSTATUS(status) ((((*(const int *) &(status))) & 0xff00) >> 8)
错误是由于地址运算符得到了错误的操作数。本质上,这个宏不能仅与表达式或变量一起使用常量,假设这些是从文档中描述的特定源返回的值。
WEXITSTATUS
宏是 C 标准库实现的问题,而不是编译器本身的问题。通常(在 GCC 的情况下)编译器不提供 C 标准库实现。是独立包。
大多数 Linux 发行版,包括 Ubuntu,使用 glibc 作为 C 标准库实现。
在 glibc 直到版本 2.23(含)中,当使用 C++ 时,宏是按以下方式定义的,并且设置了 __USE_MISC
(参见下面的提交 link):
# define __WAIT_INT(status) (*(const int *) &(status))
// ...
# define WEXITSTATUS(status) __WEXITSTATUS (__WAIT_INT (status))
宏的实际实现在__WEXITSTATUS
里面,但是使用__WAIT_INT
好像是为了支持non-POSIX》union等待" wait
界面的变体。使用此定义,纯右值不能与宏一起使用,因为它试图获取 status
.
2016 年,commit b49ab5f4503f36dcbf43f821f817da66b2931fe6 支持 union wait - 根据 1990 年代初期弃用的 NEWS
条目 - 已被删除,现在定义很简单
# define WEXITSTATUS(status) __WEXITSTATUS (status)
现在它也适用于纯右值。
似乎 Ubuntu 16.04 仍然使用该更改之前的 glibc 版本,这并不奇怪,因为它是在提交时发布的。
我不知道 POSIX 关于是否可以使用带有 int
右值而不是变量名的宏的说法。
WEXITSTATUS
不能总是直接用于对 pclose
的调用似乎是已知问题。显然,现在 glibc 中不再存在的 above-mentioned 扩展曾经(是?)也存在于(某些?)BSD 中(并且可能源自它们?)。参见例如this question, in which the answer also expresses doubts about POSIX-compliance. However, OpenBSD, mentioned in the linked question, also removed union wait in 2014. According to the changelog 自 4.3BSD(1986 年发布)以来,它已被弃用。