整数类型
头文件包含 #include <stdint.h>
,128位整数需要gcc支持才行
int8_t int16_t int32_t int64_t __int128_t
uint8_t uint16_t uint32_t uint64_t __uint128_t
整数位操作
头文件包含 #include <byteswap.h>
#include <byteswap.h>
bswap_16(x);
bswap_32(x);
bswap_64(x);
基于汇编的重新实现,128bit整数swap需要优化
static inline uint32_t _bswap32(uint32_t _x) {
uint32_t x = _x;
asm volatile("bswap %[x]" : [ x ] "+r"(x));
return x;
}
static inline uint16_t _bswap16(uint16_t _x) {
uint16_t x = _x;
asm volatile("xchgb %b[x1],%h[x2]" : [ x1 ] "=Q"(x) : [ x2 ] "0"(x));
return x;
}
static inline uint64_t _bswap64(uint64_t _x){
uint64_t x = _x;
asm volatile("bswap %[x]" : [ x ] "+r"(x));
return x;
}
static inline __uint128_t _bswap128(__uint128_t _x){
union {__uint128_t u128;uint64_t u64[2];} x;
x.u64[1]=_bswap64(_x&(uint64_t)(-1));
x.u64[0]=_bswap64((_x>>64)&(uint64_t)(-1)) ;
return x.u128;
}
应用
在项目中需要根据公式动态构建出一份c代码,ipv6部分使用128bit整数,在构建代码是使用如下方式:
typedef union ipv6_u{
__uint128_t u128;
uint64_t u64[2];
uint8_t u8[16];
} ipv6_t;
static char* op2str(int op, char opstr[]) {
switch(op) {
case EQ:
strcpy(opstr, "==");
break;
case NEQ:
strcpy(opstr, "!=");
break;
case GT:
strcpy(opstr, ">");
break;
case LT:
strcpy(opstr, "<");
break;
case GEQ:
strcpy(opstr, ">=");
break;
case LEQ:
strcpy(opstr, "<=");
break;
default:
strcpy(opstr, "==");
break;
}
return opstr;
}
static char* build_ipv6_expr(char* expr, int32_t op,
enum yytokentype direction,
ipv6_t* mask, ipv6_t* ip) {
char opstr[10];
char addr[1024];
// mask.u64[2] ip.u64[2]
// [0] -> low 64 bits for u128
// [1] -> high 64 bits for u128
if(mask->u128 != ((__uint128_t)(-1))) {
sprintf(addr, "(*(__uint128_t*)(xdr + %jd) & ((__uint128_t)(0x%08jx)<<64|0x%08jx))",
direction == IPV6_SRC ? hdr_offset.src_addrv6 : hdr_offset.dst_addrv6,
mask->u64[1], // high
mask->u64[0]); // low
} else {
sprintf(addr, "*(__uint128_t*)(xdr + %jd)",
direction == IPV6_SRC ? hdr_offset.src_addrv6 : hdr_offset.dst_addrv6);
}
op2str(op, opstr);
switch(op) {
case EQ:
case NEQ:
sprintf(expr, "%s %s ((__uint128_t)(0x%08jx)<<64|0x%08jx)", addr, opstr, ip->u64[1], ip->u64[0]);
break;
default:
// byte swap, low convert to high; high -> low
sprintf(expr, "_bswap128(%s) %s ((__uint128_t)(0x%08jx)<<64|0x%08jx)", addr, opstr, bswap_64(ip->u64[0]), bswap_64(ip->u64[1]));
break;
}
return expr;
}
生成的代码如下:
(*(__uint128_t*)(xdr + 24) == ((__uint128_t)(0x100000000000000)<<64|0x5000000020000fc) || *(__uint128_t*)(xdr + 40) == ((__uint128_t)(0x100000000000000)<<64|0x5000000020000fc))
备注
- 为什么使用
((__uint128_t)(0x%08jx)<<64|0x%08jx)
a.snprintf
无法打印128bit整数;
b.c/c++
代码中,无法直接常亮表示128bit
整数,编译时会报错warning: integer constant is too large for its type
c. 生成代码((__uint128_t)(0x100000000000000)<<64|0x5000000020000fc)
可在编译时,由编译器优化。