比较结构指针,丢弃成员和UB [英] Comparing struct pointers, casting away members, and UB

查看:85
本文介绍了比较结构指针,丢弃成员和UB的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

int main()
{
    typedef struct { int first; float second; } type;

    type whole = { 1, 2.0 };
    void * vp = &whole;

    struct { int first; } * shorn = vp;
    printf("values: %d, %d\n", ((type *)vp)->first, shorn->first);
    if (vp == shorn)
        printf("ptrs compare the same\n");

    return 0;
}

两个问题:


  1. 指针相等性比较UB是吗?

  2. 关于剪切?初始化 shorn 的行上的 second 成员:丢弃这样的struct成员是否有效C?然后取消引用操纵指针以访问其余成员?

  1. Is the pointer equality comparison UB?
  2. Regarding the "shearing" away of the second member on the line that initializes shorn: is it valid C to cast away struct members like this and then dereference the manipulated pointer to access the remaining member?


推荐答案

6.2节。 5类型 C标准的 28 段说:


[...]所有指向结构类型的指针都应具有相同的表示和对齐要求。 [...]

[...] All pointers to structure types shall have the same representation and alignment requirements as each other. [...]

6.3.2.3指针段落 1 说:


指向 void 的指针可以与任何对象类型的指针进行转换。指向任何对象类型的指针都可以转换为指向 void 的指针,然后再次返回;结果应该等于原始指针。

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

7 段说:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果对于所引用的类型,结果指针未正确对齐 68),则行为未定义。否则,当再次转换回时,结果应等于原始指针。 [...]

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. [...]

脚注 68 说:


通常,正确对齐的概念是指正确对齐。是可传递的:如果类型A的指针与类型B的指针正确对齐,又为类型C的指针正确对齐,则类型A的指针对于类型C的指针正确对齐。

In general, the concept "correctly aligned" is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C.

由于所有指向结构类型的指针都具有相同的表示形式,因此指向 void 的指针与指向所有指向结构类型的指针的结构类型必须相同。因此,似乎可以由类型转换运算符将指向结构类型A的指针直接转换为指向结构类型B的指针,而无需中间转换为指向 void 的指针,只要指针被正确对准。

Because all pointers to structure types have the same representation, the conversions between pointers to void and pointers to structure types must be the same for all pointers to structure types. So it seems that a pointer to structure type A could be converted by a cast operator directly to a pointer to structure type B without an intermediate conversion to a pointer to void as long as the pointer is "correctly aligned" for structure type B. (This may be a weak argument.)

对于两个结构类型A和B,当结构类型A的初始序列包括以下内容时,问题仍然存在:对于结构类型B的所有成员,保证结构类型A的指针正确对齐(显然不能保证反向)。据我所知,C标准没有这样的保证。因此严格来说,指向较大结构类型A的指针可能无法与较小结构类型B正确对齐,如果没有,则行为是不确定的。对于理智的人,在编译器中,较大的结构类型A不会比较小的结构类型B具有较弱的对齐方式,但是对于疯狂的结构而言,

The question remains when, in the case of two structure types A and B where the initial sequence of structure type A consists of all the members of structure type B, a pointer to structure type A is guaranteed to be correctly aligned for structure type B (the reverse is obviously not guaranteed). As far as I can tell, the C standard makes no such guarantee. So strictly speaking, a pointer to the larger structure type A might not be correctly aligned for the smaller structure type B, and if it is not, the behavior is undefined. For a "sane" compiler, the larger structure type A would not have weaker alignment than the smaller structure type B, but for an "insane" compiler, that might not be the case.

关于第二个问题,即使用从完整(较长的结构),则只要指针针对较短的结构正确对齐即可(请参见上文,了解疯狂编译器为何不正确),并且只要避免使用严格的别名规则(例如,通过中间指针指向跨编译单元边界的中间外部函数调用中的void),然后通过指向较短结构类型的指针访问成员应该是非常好的。当两种结构类型的对象显示为相同联合类型的成员时,存在特殊保证。 6.3.2.3结构和工会成员段落 6 说:

Regarding the second question about accessing members of the truncated (shorter) structure using the pointer derived from the full (longer) structure, then as long as the pointer is correctly aligned for the shorter structure (see above for why that might not be true for an "insane" compiler), and as long as strict aliasing rules are avoided (for example, by going through an intermediate pointer to void in an intermediate external function call across compilation unit boundaries), then accessing the members through the pointer to the shorter structure type should be perfectly fine. There is a special guarantee for that when objects of both structure types appear as members of the same union type. Section 6.3.2.3 Structure and union members paragraph 6 says:


为了简化并集的使用:如果一个并集包含几个共享一个共同的初始序列的结构(请参见下文),并且如果并集
对象当前包含这些结构之一,则允许检查该共同的初始部分其中任何一个可以看到已完成工会
声明的地方。如果一个或多个初始成员的序列的对应成员具有兼容的类型(对于位域,宽度相同),则两个结构共享一个公共初始序列

但是,由于结构类型内成员的偏移量不取决于结构类型的对象是否以联合类型出现,因此上述含义暗示任何具有共同点的结构成员的初始序列将使这些公共成员在其各自的结构类型中具有相同的偏移量。

However, since the offsets of members within a structure type does not depend on whether an object of the structure type appears in a union type or not, the above implies that any structures with a common initial sequence of members will have those common members at the same offsets within their respective structure types.

这篇关于比较结构指针,丢弃成员和UB的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆