我已经编写了这个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 *
的转换是可移植的吗? (这会令人遗憾地输出编译器警告,但我想您还是会得到带有“正常”标记指针的警告...)
答案 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语义的同时竭尽全力打破这一局面。