如何在C中将指针的最右位设置为1

Rob*_* Lu 1 c pointers bit-manipulation

我需要在最右边的位标记一个int指针的地址,并将该地址存储在某处.例如,0x10处的地址将变为0x11.

我试过了

int* addr = some_pointer;
int* tagged = (int*) (addr | 0x00000001);
Run Code Online (Sandbox Code Playgroud)

但我得到错误:二进制表达式的无效操作数('int*'和'int').我怎么能这样做?

chu*_*ica 7

如何将指针的最右位设置为1?

C99/C11提供可选的整数类型,(u)intptr_t用于将void*指针转换为整数,然后转换回指针.该往返导致指针的与原始相等.它可能具有或不具有与原始指针相同的位模式.

#include <stdint.h>
int i = 42;
int* addr = &i;
void *vptr = addr;
uintptr_t uptr = (uintptr_t) vptr;

// Set least significant bit.
uintptr_t uptr1 = uptr | 1;
// or one-liner
uintptr_t uptr1 = ((uintptr_t) (void *) &i) | 1;
Run Code Online (Sandbox Code Playgroud)

没有打印说明符(u)intptr_t,因此代码可以转换为最宽的类型以用于显示目的

printf("%p --> %ju --> %ju\n", vptr, (uintmax_t) uptr, (uintmax_t) uptr1); 
// or use macros from <inttypes.h>
printf("%p --> %" PRIuPTR " --> %" PRIuPTR "\n", vptr, uptr, uptr1); 
Run Code Online (Sandbox Code Playgroud)

只要OP只需要将值存储为整数,就没问题了.(u)intptr_t源自有效指针的值可以转换回匹配的指针类型,没有任何问题.

到目前为止这么好,但OP可能想要使用被操纵的值.

现在的诀窍是uptr1可能会或可能不会转换为有效的void *指针.即使它确实转换为有效 void *指针,转换为a int *可能也可能不起作用.这两个步骤超出了C规范 - 未定义的行为.

// UB
void *vptr1 = (void *) uptr1;
printf("%p\n", vptr1); 
int *iptr1 = vptr1;
Run Code Online (Sandbox Code Playgroud)

如果代码到目前为止,尝试取消引用这个新指针,它也是UB.

printf("%d\n", *iptr1);       // UB, good luck
Run Code Online (Sandbox Code Playgroud)

  • 我从来没有想过通过"你以后可以用'uniptr_t`值做什么"?那是很好的讨论.就像提供的类型允许处理一些角落情况的int-to-pointer-back转换一样,但不是很多.我想我还没有碰到那些情况.做得好. (2认同)