typedef struct { char ch; int num; } st_t;
typedef union { char *pch; st_t *pst; } un_t;
st_t st;
st.ch = 's';
un_t un = { &st.ch };
*un.pch = 'u';
printf("%c\n", un.pst->ch); // expect: print the letter 'u'
据我所知,结构的第一个成员的地址和结构本身的地址是相同的,因此un
都可以指向st
和st.ch
同时访问pst
和pch
。但是,C99标准似乎从未明确说过the sizes of different types of pointers are identical。那么,我担心的是代码是否会被破坏,例如违反严格的别名规则,未定义的行为等等?
答案 0 :(得分:1)
该行:
un_t un = {&st.ch};
*un.pch = 'u';
将结构的成员ch的地址分配给union的成员pch,然后使用该指针将字符写入该地址。这是完全正确的。
以下行存在问题:
printf("%c\n", un.pst->ch);
读取工会成员,而不是最后存入的工会成员 以下可能是陷阱 1 表示 2 :
un.pst
1 (引自:ISO / IEC 9899:201x 6.2.6.1概述5)
某些对象表示不需要表示对象类型的值。如果存储
对象的值具有这样的表示,并由左值表达式读取
没有字符类型,行为是未定义的。如果产生这样的表示
通过副作用,通过左值表达式修改对象的全部或任何部分
没有字符类型,行为未定义。 50)这种表示被称为
陷阱表示。
2 (引自:ISO / IEC 9899:201x 6.5.2.3结构和工会成员3脚注95))
如果用于读取union对象内容的成员与上次使用的成员不同
在对象中存储一个值,该值的对象表示的相应部分被重新解释
作为6.2.6中描述的新类型中的对象表示(有时称为''类型的过程)
双关语””)。这可能是陷阱表示。
答案 1 :(得分:0)
虽然这样的构造并不严格符合关于指针大小的标准,但实际上最常见的实现(即msvc,gcc / linux)对非函数指针使用相同的表示。
所以在这些实现上,它应该像你期望的那样工作。
答案 2 :(得分:0)
C标准试图定义所有符合要求的实现所需的特征,特征和保证;它不会努力描述99%的实现中常见的大多数有用的特性和功能,但这些特性和功能并不是必需的。
在绝大多数实现中,所有数据指针使用相同的表示,因此thingType *foo=xxx; void *vfoo = foo;
给出foo
并且vfoo
将保持相同的位模式。在积极的日子之前
优化器,这样的实现将非常有用地允许任何类型的数据
要使用void**
访问的指针,因此可以编写如下函数:
int realloc_if_possible(void **p, int newsize)
{
void *temp = realloc(*p, newsize);
if (!temp) return -1;
*p = temp;
return 0;
}
但由于C标准不要求编译器识别别名 函数传递除void *之外的任何指针的地址, 许多现代编译器不再支持此类构造,除非所有类型都基于类型 别名优化被禁用。