下面的代码段进行编译,

#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

注:

奇怪的是,我无法在godbolt.org上重现上述现象.It compiles on godbolt.orggcc 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);
}

有人能解释一下这件事吗?

100:

我现在可以重现错误了!请参见此link.

100:

这只是一个简单的例子.我实际上面对的是WEXITSTATUS(pclose(fp))不编译.

推荐答案

WEXITSTATUS宏是C标准库实现的问题,而不是编译器本身.通常(在GCC的情况下)编译器不提供C标准库实现.这是一个独立的包.

大多数Linux发行版,包括Ubuntu,都使用glibc作为C标准库实现.

在glibc 2.23(含2.23)之前的版本中,当使用C++并设置为__USE_MISC时,宏的定义方式如下(请参见下面的提交链接):

#   define __WAIT_INT(status)   (*(const int *) &(status))

// ...

# define WEXITSTATUS(status)    __WEXITSTATUS (__WAIT_INT (status))

宏的实际实现在__WEXITSTATUS之内,但__WAIT_INT的使用似乎是为了支持wait接口的非POSIX"union wait"变体.根据此定义,prvalue不能与宏一起使用,因为它试图获取status的地址.

2016年,根据20世纪90年代初反对的NEWS个条目,union waitcommit b49ab5f4503f36dcbf43f821f817da66b2931fe6个支持被删除,现在的定义很简单

# define WEXITSTATUS(status)    __WEXITSTATUS (status)

现在它也可以使用prvalue.

看起来Ubuntu 16.04仍在使用之前的glibc版本,这并不奇怪,因为它是在提交时发布的.

我不知道POSIX对是否可以将宏与int rvalue而不是变量名称一起使用有何 comments .

WEXITSTATUS不能总是直接用于呼叫pclose,这似乎是已知的问题.显然,上述扩展现在不再存在于glibc中了,它是(is?)也存在于(某些?)BSD(可能源于BSD?).参见示例this question,其中的答案也表示对POSIX合规性的怀疑.然而,链接问题中提到的OpenBSD在2014年也删除了union wait个.根据changelog,自4.3BSD(1986年发布)以来,它一直被弃用.

Linux相关问答推荐

创建守护进程时打开0,1,2描述符

我想强调某些条件是否与Linux中的全部输出匹配

在shell 中使用排除模式的grep

通过ssh传输参数时避免字符串拆分

没有发现运行时依赖关系,但它在S的运行时路径中有吗?

我可以在不调用 shell 的情况下使用 popen() 吗?在 C++ 中

如何删除文件中不需要的字符(使用 shell 脚本)

Rust unix 进程

awk 不打印所需的 df 输出

文件未在脚本中使用 cp 命令复制到 Docker 容器中

Bash 更新 yaml 文件中的图像值

哪个程序在给定任何文件的情况下创建一个 C 数组?

使用 linux 命令行 (bash) 从网络摄像头拍照

exec 系统调用(如 exec 和 execve)系列的功能有什么区别?

./studio.sh 之后的 Android Studio 错误

根据日期范围过滤日志(log)文件条目

如何仅打印 hexdump 中的十六进制值,而不打印行号或 ASCII 表?

使用sudo apt-get install build-essentials

初学者如何在 Linux 中开始使用 Mono?

CentOS:在 PHP 安装中启用 GD 支持