对齐宏的位运算描述
#define alignment_mask(size) (~(size-1))
#define alignment_down(a, size) (a & alignment_mask(size) )
#define alignment_up(a, size) ((a+size-1) & alignment_mask(size))
一般对齐都是按照 2 的指数值来对齐的,~(size-1) 本质是 size 的相反数。如果 size 是2的指数,那么 ~(size-1) 就是符号位从 0 变为 1。前边是连续的 1,后边是连续的 0 这种形式,例如 1111111100000.
位运算特性
1 | 0 | |
---|---|---|
与 & | 保持 | 置0 |
或 | | 置1 | 保持 |
异或 ^ | 取反 | 保持 |
3种运算,每种都有一个结果是保持,刚好利用这个特性来针对特定的位来进行操作 – 置1,置0,取反。
对于任意的 int x
,在内存中都是使用补码表示。~x + 1
肯定就是 x
的相反数。x + ~x + 1
的结果肯定是0(x + ~x
肯定是全 1,值是 - 1)。
将 ~(x - 1)
求相反数,取反加 1 即可。~(~(x - 1)) + 1 = x
,所以 ~(x - 1)
是 x
的相反数。
size
是2的指数时, (~(size-1))
是前边全 1,后边全 0 的形式,所以 a & (~(size-1))
,相当于将右边低位多余对齐单位的全部置 0,高位保持不变,就是向下对齐。如果是向上对齐,需要加上越过一个对齐单位,通过加上 ~(size-1)
来实现进 1 向上对齐。
对齐宏的算术运算描述
#define zero_or_one(x) ((x > 0) ? 1 : 0)
#define alignment_down(a, size) (a - a % size )
#define alignment_up(a, size) (a - (a % size) + zero_or_one(a % size) * size)
结果
printf("up align %d\n", alignment_down(6, 8)); //0
printf("up align %d\n", alignment_down(8, 8)); //8
printf("up align %d\n", alignment_down(14, 8)); //8
printf("up align %d\n", alignment_up(6, 8)); //8
printf("up align %d\n", alignment_up(8, 8)); //8
printf("up align %d\n", alignment_up(14, 8)); //16
Linux 编程相关
recvmsg 和 sendmsg 函数接口中的 struct msghdr
消息头结构中的 struct cmsghdr
.
struct cmsghdr {
size_t cmsg_len; /* Data byte count, including header
(type is socklen_t in POSIX) */
int cmsg_level; /* Originating protocol */
int cmsg_type; /* Protocol-specific type */
/* followed by
unsigned char cmsg_data[]; */
};
消息头结构中的辅助信息的设置,涉及到对齐的两个宏操作:
- CMSG_SPACE() returns the number of bytes an ancillary element with payload of the passed data length occupies. This is a constant expression.
- CMSG_LEN() returns the value to store in the cmsg_len member of the cmsghdr structure, taking into account any necessary alignment. It takes the data length as an argument. This is a constant
expression.
里边都是间接的操作CMSG_ALIGN
结构。一条消息可以有多条辅助数据,辅助数据构成辅助数组,所以此时必须按数组中的对齐,使用CMSG_SPACE
. 消息头中的msg_controllen
字段是所有的辅助信息的总长度。
#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
& (size_t) ~(sizeof (size_t) - 1))