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-02-08 16:41:11 +08:00
我试了一下,这样写可以:
enum A { X = __builtin_bswap32(1), }; 估计还是为了什么兼容性吧。 |
2
minami 2023-02-08 16:53:00 +08:00
那你用__constant_htonl 呗
|
3
ysc3839 2023-02-08 21:59:38 +08:00 via Android
C++的话自己实现个 constexpr 的即可,C 不行。
|
4
ysc3839 2023-02-08 22:08:31 +08:00 via Android 1
__DARWIN_OSSwapConstInt32 这个应该是编译器的 intrinsic 。按照 BSD socket 的标准,htonl 应该是个函数来的,Linux 实现成了一个函数,所以不支持。
你要编译期且跨平台的话,用 C++的 std::endian 加上 if constexpr 是最简单的。 C 的话可以用编译器提供的字节序宏以及翻转字节序的 intrinsic 。 |