字节顺序宏未正确定义[关闭]

Posted

技术标签:

【中文标题】字节顺序宏未正确定义[关闭]【英文标题】:Endianess macros not correctly defined [closed] 【发布时间】:2020-02-19 20:52:35 【问题描述】:

我正在尝试编译 grpc,其中一个目标使用 /usr/include/netinet/tcp.h,其中包含以下内容:

# if __BYTE_ORDER == __LITTLE_ENDIAN
        uint8_t th_x2:4;        /* (unused) */
        uint8_t th_off:4;       /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
        uint8_t th_off:4;       /* data offset */
        uint8_t th_x2:4;        /* (unused) */
# endif

不知何故,这两个条件都满足了,导致编译失败(error: duplicate member 'th_off')。我写了一个测试C程序,好像三个宏定义不正确。

我尝试重新安装gccg++,并将它们降级到以前的版本。我还尝试重新安装 Linux 头文件。终于尝试用clang编译了,还是不行。

我的两台测试计算机都运行 Ubuntu 19.10,它们的结果都是一样的。定义这些宏是否需要编译器标志或系统配置?

编辑:tcp.h 是系统标头。它不是我写的,它几乎是全新安装的 Ubuntu,标准安装为 build-essentials

编辑 2:我使用了一个测试程序,在这种情况下它可以正常工作。它显示little

#include <iostream>
#include <netinet/tcp.h>

int main() 
#if __BYTE_ORDER == __LITTLE_ENDIAN
    std::cout << "little\n";
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
    std::cout << "big\n";
#endif

【问题讨论】:

__LITTLE_ENDIAN__BIG_ENDIAN 是两个不同的常量,所以它们不能相等。在源代码的某个地方,它们已被重新定义。 @stark 他说它们根本没有定义,所以预处理器将它们全部视为0 如果你printf("BE: %d\nLE: %d\nBO: %d\n", __BIG_ENDIAN, __LITTLE_ENDIAN, __BYTE_ORDER)你会得到什么 @stark 我看到它们在/usr/include/endian.h 中定义。 bits/endian.h 只是将__BYTE_ORDER 定义为其中之一。 我在我的问题中添加了测试程序结果 【参考方案1】:

在我的 Debian 系统上,__LITTLE_ENDIAN__BIG_ENDIAN/usr/include/endian.h 中定义。我相信此文件旨在跨架构通用。

__BYTE_ORDER 被定义为/usr/include/bits/endian.h 中的其中之一。我认为bits 目录包含特定于特定架构的标头。

tcp.h 包括&lt;types.h&gt;,我认为应该间接包括这些并定义宏。我不确定为什么它没有发生在你身上。

【讨论】:

在我的系统上,netinet/tcp.h 包括 sys/types.h,并且我看到的唯一包含到 endian.h 的内容是如果定义了 __USE_BSD 在我的 Ubuntu 19.10 机器上,如果定义了 __USE_MISC,则包含 &lt;endian.h&gt;。但是,如果 __USE_MISC 没有定义,那么 &lt;netinet/tcp.h&gt; 永远不会首先尝试声明有问题的结构。 这里一样,几乎整个标题都在#ifdef __USE_MISC内。 在包含第一个标准标头后,可能会重新定义功能测试宏(或它们的 glibc 内部代理,如 __USE_MISC),从而导致暴露的内容不一致。例如,如果 &lt;sys/types.h&gt; 已经包含在不公开 &lt;endian.h&gt; 的 FTM 中,那么稍后在包含 &lt;netinet/tcp.h&gt; 之前更改了宏,则如 OP 所见,字节序宏将丢失。【参考方案2】:

您可以使用 gcc 内置函数:

# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        uint8_t th_x2:4;        /* (unused) */
        uint8_t th_off:4;       /* data offset */
# endif
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        uint8_t th_off:4;       /* data offset */
        uint8_t th_x2:4;        /* (unused) */
# endif

在c预处理器中,两个不存在的宏是相等的。

来源:https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html

【讨论】:

为什么系统头文件会有错误的宏?顺便说一句,我刚刚检查了我的 Debian 系统,和问题中的一样。 这些是 gcc 内置函数,而不是头文件常量 正如@Barmar 所说,我没有编辑文件,它是这样的...... "你可以使用 gcc builtins" - 注意这是一个系统头文件。更改系统头文件通常不是一个好主意。 @user3684240 OP 没有该选项。这是一个系统头文件。

以上是关于字节顺序宏未正确定义[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Uart 接收到正确的字节,但顺序混乱

C# 将字节解析为结构顺序

如何以相反的字节顺序打印变量?

字节序

网络字节顺序为大端模式

自定义缓冲区的字节顺序