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

时间:2018-07-01 17:02:11

标签: c pointers language-lawyer portability

我已经编写了这个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);
}

但是,我很好奇它是否真的是便携式的。

虽然数组操作部分是可移植的,但假设char *引用了struct *中的第一个字段/元素,则char *struct *的转换是可移植的吗? (这会令人遗憾地输出编译器警告,但我想您还是会得到带有“正常”标记指针的警告...)

1 个答案:

答案 0 :(得分:2)

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

如果插入强制转换#define UNTAG(x) ((tagged int *)(&(x)[-*(x)])),则根据C 2011(草案N1570)6.7.2.1 15,“结构对象的指针经过适当转换后,指向其初始成员(或如果该成员是位字段,则指向它所在的单元,反之亦然。”这里的障碍是您拥有指向第一个成员的第一个成员的指针(即,指向{{1 }},它是数组的第一个成员的元素0)。根据您对C标准中某些内容的解释的严格程度,可能会或可能不会认为它受支持(并且可能会使用char中的两个强制转换来缓解这种情况)。无论如何,我都希望它具有可移植性,因为C实现必须在支持其他公认的C语义的同时竭尽全力打破这一局面。