簡體   English   中英

關於 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上重現上述現象。 在 godbolt.org上編譯為gcc 4.9.3gcc 4.9.4不可用)。

這是 g++ 的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))不編譯。

WEXITSTATUS宏是 C 標准庫實現的問題,而不是編譯器本身的問題。 通常(在 GCC 的情況下)編譯器不提供 C 標准庫實現。 是一個獨立的package。

大多數 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似乎是為了支持wait接口的非 POSIX“聯合等待”變體。 使用此定義,純右值不能與宏一起使用,因為它試圖獲取status的地址。

2016 年, 提交 b49ab5f4503f36dcbf43f821f817da66b2931fe6支持聯合等待——根據 1990 年代初期棄用的NEWS條目——已被刪除,現在的定義很簡單

# define WEXITSTATUS(status)    __WEXITSTATUS (status)

現在它也適用於純右值。

似乎 Ubuntu 16.04 仍然使用該更改之前的 glibc 版本,這並不奇怪,因為它是在提交時發布的。

我不知道 POSIX 對是否可以使用帶有int右值而不是變量名的宏有什么看法。

WEXITSTATUS不能總是直接用於調用pclose似乎是已知問題。 顯然,上面提到的擴展,現在不再出現在 glibc 中,曾經(現在?)也出現在(某些?)BSD 中(並且可能源自它們?)。 參見例如這個問題,其中的答案也表達了對 POSIX 合規性的懷疑。 但是,鏈接問題中提到的 OpenBSD 也在 2014 年刪除了union wait 。根據變更日志,自 4.3BSD(1986 年發布)以來它已被棄用。

這看起來像是一個奇怪的宏實現,導致運算符優先級出現問題。 通常它應該是這樣的:

#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)

錯誤發生於地址運算符得到錯誤的操作數。 本質上,該宏不能僅與表達式或變量一起使用常量,假設這些是從文檔中描述的特定源返回的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM