
Mac 中编译通过的代码在 Linux 中编译不通,问题在于 enum 中使用了 htonl:
enum A { X = htonl(1), }; 报错:
./****: error: expression is not an integral constant expression X = htonl(1), ^~~~~~~~ /usr/include/netinet/in.h:404:21: note: expanded from macro 'htonl' # define htonl(x) __bswap_32 (x) ^~~~~~~~~~~~~~ ./****: note: non-constexpr function '__bswap_32' cannot be used in a constant expression 而 Mac 中 htonl 是这样的:
#define htonl(x) __DARWIN_OSSwapInt32(x) #define __DARWIN_OSSwapInt32(x) \ (__builtin_constant_p(x) ? __DARWIN_OSSwapConstInt32(x) : _OSSwapInt32(x)) 如果是常量,直接用 __DARWIN_OSSwapConstInt32 宏算出结果,不是常量则在运行时 bswap 计算。所以 htonl(常量) 能在 enum 中使用。
为什么 Linux 没有实现这个特性?
Linux: 5.4.0-126-generic (clang version 10.0.0-4ubuntu1) MacOS: 22.1.0 Darwin (Apple clang version 14.0.0) 1 tool2d 2023 年 2 月 8 日 我试了一下,这样写可以: enum A { X = __builtin_bswap32(1), }; 估计还是为了什么兼容性吧。 |
2 minami 2023 年 2 月 8 日 那你用__constant_htonl 呗 |
3 ysc3839 2023 年 2 月 8 日 via Android C++的话自己实现个 constexpr 的即可,C 不行。 |
4 ysc3839 2023 年 2 月 8 日 via Android __DARWIN_OSSwapConstInt32 这个应该是编译器的 intrinsic 。按照 BSD socket 的标准,htonl 应该是个函数来的,Linux 实现成了一个函数,所以不支持。 你要编译期且跨平台的话,用 C++的 std::endian 加上 if constexpr 是最简单的。 C 的话可以用编译器提供的字节序宏以及翻转字节序的 intrinsic 。 |