这是一种在C中做标记指针的可移植方式吗?

Son*_*Ex2 5 c portability pointers language-lawyer

我编写了这个C代码,我假设它提供了可移植的标记指针:

typedef struct {
    char tag[2];
    int data;
} tagged_int;

#define TAG(x,y) (&(x)->tag[(y)])
#define UNTAG(x) (&(x)[-*(x)])

int main(void) {
    tagged_int myint = {{0,1}, 33};
    tagged_int *myptr = &myint;

    char *myint_tag_1 = TAG(myptr,1);
    char *myint_tag_0 = TAG(myptr,0);

    char tag_1 = *myint_tag_1;
    char tag_0 = *myint_tag_0;

    tagged_int *myint_1 = UNTAG(myint_tag_1);
    tagged_int *myint_0 = UNTAG(myint_tag_0);
}
Run Code Online (Sandbox Code Playgroud)

但是,我很好奇它是否真的可携带.

虽然数组操作部分是可移植的,但是转换是char *struct *移植的,假设char *指的是第一个字段/元素struct *?(这很遗憾地输出编译器警告,但我猜你会得到带有"正常"标记指针的那些......)

Eri*_*hil 2

#define UNTAG(x) (&(x)[-*(x)])不用作指向tagged_int;的指针 它是一个char *并且不会自动转换。

\n\n

如果插入强制转换,#define UNTAG(x) ((tagged int *)(&(x)[-*(x)]))那么这几乎是合法的,根据 C 2011 (draft N1570) 6.7.2.1 15, \xe2\x80\x9cA 指向结构对象的指针,经过适当转换,指向其初始成员(或者如果该成员是一个位域,然后指向它所在的单元),反之亦然。\xe2\x80\x9d 这里的一个障碍是你有一个指向第一个成员的第一个成员的指针(即指向char一个数组的第 0 个元素,即第一个成员)。根据您对 C 标准中某些内容的解释严格程度,这可能会也可能不会被视为受支持(并且可以通过使用两次强制转换来缓解,如#define UNTAG(x) ((tagged int *)(char (*)[2])(&(x)[-*(x)])))。无论如何,我希望它是可移植的,因为 C 实现必须不遗余力地打破这一点,同时支持其他可接受的 C 语义。

\n