C 检查并对齐缓冲器

C 检查并对齐缓冲器,c,memory,alignment,buffer,C,Memory,Alignment,Buffer,我试图理解如何检查指针是否对齐,并最终对齐它 为了理解它,我采用以下函数: #define PJ_POOL_ALIGNMENT 8 PJ_DEF(pj_pool_t*) pj_pool_create_on_buf(const char *name, void *buf, pj_size_t size) { #if PJ_HAS_POOL_ALT_API == 0 struct creation_param param; pj_

我试图理解如何检查指针是否对齐,并最终对齐它

为了理解它,我采用以下函数:

#define PJ_POOL_ALIGNMENT 8

PJ_DEF(pj_pool_t*) pj_pool_create_on_buf(const char *name,
                 void *buf,
                 pj_size_t size)
{
#if PJ_HAS_POOL_ALT_API == 0
struct creation_param param;
pj_size_t align_diff;

PJ_ASSERT_RETURN(buf && size, NULL);

if (!is_initialized) {
if (pool_buf_initialize() != PJ_SUCCESS)
    return NULL;
is_initialized = 1;
}

/* Check and align buffer */
align_diff = (pj_size_t)buf;
if (align_diff & (PJ_POOL_ALIGNMENT-1)) {
    align_diff &= (PJ_POOL_ALIGNMENT-1);
    buf = (void*) (((char*)buf) + align_diff);
    size -= align_diff;
}

param.stack_buf = buf;
param.size = size;
pj_thread_local_set(tls, &param);

return pj_pool_create_int(&stack_based_factory, name, size, 0, 
              pj_pool_factory_default_policy.callback);
#else
PJ_UNUSED_ARG(buf);
return pj_pool_create(NULL, name, size, size, NULL);
#endif
}
显然,我感兴趣的部分是/*检查并对齐缓冲区*/ 我想我唯一能理解的是:

让我们关注一下if。 这是为了验证缓冲区是否与8字节多址对齐。如果If的条件未对齐,则返回除0以外的数字,然后执行对齐,否则,仅存在一个带1的位即可跳过If。为了获得这个结果,他们将变量PJ_POOL_对齐为7(0111),并以此为基础,使用分配缓冲区的地址进行and。考虑到如果地址未对齐,我希望获得除0以外的数字,操作如下

万。0111和

xxxx。x100


万。0100未对齐

如果最后3位中的任何一位中有1(或更多1),因此我知道它未与8字节块对齐:x且1=0,则if将为真。然后它将进入校正块

但if块对我来说并不清楚。
可以确认我的推理是否正确并让我理解该块的人。

当前对齐代码不正确。它确定与下部路线边界的路线差异,并将其错误地添加到指针值以达到上部路线边界:

xxxxx000 + 000 = xxxxx000 (OK - no change)
xxxxx001 + 001 = xxxxx010 (WRONG)
xxxxx010 + 010 = xxxxx100 (WRONG)
xxxxx011 + 011 = xxxxx110 (WRONG)
xxxxx100 + 100 = xxxxy000 (OK - rounded up)
xxxxx101 + 101 = xxxxy010 (WRONG)
xxxxx110 + 110 = xxxxy100 (WRONG)
xxxxx111 + 111 = xxxxy110 (WRONG)
与上定线边界的差值是与下定线边界差值的2的补充,以定线尺寸为模:

xxxxx000 + 000 = xxxxx000 (OK - no change)
xxxxx001 + 111 = xxxxy000 (OK - rounded up)
xxxxx010 + 110 = xxxxy000 (OK - rounded up)
xxxxx011 + 101 = xxxxy000 (OK - rounded up)
xxxxx100 + 100 = xxxxy000 (OK - rounded up)
xxxxx101 + 011 = xxxxy000 (OK - rounded up)
xxxxx110 + 010 = xxxxy000 (OK - rounded up)
xxxxx111 + 001 = xxxxy000 (OK - rounded up)

可以通过添加一行来更正当前对齐代码,以将下部对齐差异转换为上部对齐差异:

/* Check and align buffer */
align_diff = (pj_size_t)buf;
if (align_diff & (PJ_POOL_ALIGNMENT-1)) {
    align_diff &= (PJ_POOL_ALIGNMENT-1);
    align_diff = PJ_POOL_ALIGNMENT - align_diff; // upper alignment
    buf = (void*) (((char*)buf) + align_diff);
    size -= align_diff;
}
/* Check and align buffer */
align_diff = (pj_size_t)-(pj_size_t)buf & (PJ_POOL_ALIGNMENT-1);
buf = (void*) (((char*)buf) + align_diff);
size -= align_diff;
或者,如果,则可以直接在
之前确定上部对齐差异:

/* Check and align buffer */
align_diff = (pj_size_t)-(pj_size_t)buf & (PJ_POOL_ALIGNMENT-1);
if (align_diff != 0) {
    buf = (void*) (((char*)buf) + align_diff);
    size -= align_diff;
}
有人可能会说(而且一直如此!)这比原始版本可读性差

事实上,
if
可以省略,因为加零没有区别:

/* Check and align buffer */
align_diff = (pj_size_t)buf;
if (align_diff & (PJ_POOL_ALIGNMENT-1)) {
    align_diff &= (PJ_POOL_ALIGNMENT-1);
    align_diff = PJ_POOL_ALIGNMENT - align_diff; // upper alignment
    buf = (void*) (((char*)buf) + align_diff);
    size -= align_diff;
}
/* Check and align buffer */
align_diff = (pj_size_t)-(pj_size_t)buf & (PJ_POOL_ALIGNMENT-1);
buf = (void*) (((char*)buf) + align_diff);
size -= align_diff;
关于
align_diff=(pj_size_t)-(pj_size_t)buf和(pj_POOL_ALIGNMENT-1)
(pj_size_t)buf
将指针转换为无符号整数类型,
-
对值求反,初始的
(pj_size_t)
使用2的补码算法将求反的值转换为无符号整数类型。
&(PJ_池_对齐-1)
将模
PJ_池_对齐
等效为
%PJ_池_对齐
(因为
PJ_池_对齐
是2的幂)

严格地说,为了避免未定义的行为,上面指向整数转换的指针应该使用
uintpttr\u t
(由
\include
定义)而不是
pj\u size\u t

align_diff = (uintptr_t)-(uintptr_t)buf & (PJ_POOL_ALIGNMENT-1);
关于
buf=(void*)((char*)buf)+align_diff
,指针算法不允许在
void*
值上使用(至少在标准C中是这样),因此
(char*)buf
将其转换为指向
char
的指针。由于
sizeof(char)
定义为1字节,因此
+align_diff
会根据需要将指针向前移动
align_diff
字节。
(void*)
然后将其转换回
void*
,然后再将其分配回
buf
。此
(void*)
在C中可以省略(但在C++中不能省略),因此该语句可以重写为:

buf = (char*)buf + align_diff;

基本上,对齐一个块意味着将其起始地址四舍五入到对齐的下一个倍数。对我来说,这个代码看起来很奇怪。我希望有一行额外的代码:
align\u diff=PJ\u POOL\u ALIGNMENT-align\u diff。您的
align_diff
计算需要按照上面@Gerhardh的建议进行更正。您可以在一条语句中计算
align_diff
,使用2对无符号类型的补码求反规则:
align_diff=(pj_size_t)((pj_size_t)buf)和(pj_POOL_ALIGNMENT-1)。请澄清:这是您的代码吗?你是否试图理解其他人的代码,或者这就是你所尝试的,你想理解为什么它不起作用?这不是我的代码,而是一个试图研究的项目的代码:我已经通过电子邮件向项目邮件列表发送了一份错误报告。我将添加
align_diff=(pj_size_t)-(pj_size_t)buf&(pj_POOL_ALIGNMENT-1)到我的“如何编写同事不懂的C”指南。谢谢。@4386427也许您应该将其添加到“如何给同事留下深刻印象和惊喜”指南中:不,没有印象。。。而是在我的“如何确保您的代码在审查中被拒绝”指南中