J. *_*Doe 18 c pointers casting undefined-behavior
/* This can be a malloc wrapper with minimal initialization. */
other_t *make_other(void);
/* This struct is never defined. */
struct undef;
typedef struct undef undef_t;
undef_t *make_undef(void)
{
other_t *other = make_other();
return (undef_t*)other;
}
Run Code Online (Sandbox Code Playgroud)
假设undef_t程序中的所有指针都是铸造other_t指针,并进一步假设所有程序在使用之前undef_t*将它们转换为铸造指针other_t*.
根据C99标准的第6.3.2.3节,return如果other未正确对齐,则语句中的强制转换会调用未定义的行为undef_t,但如果是,则将make_undef返回的结果转换为other_t*生成返回的原始指针make_other.但是,undef_t是一个未定义的类型,我找不到任何关于这些的对齐规则.这些转换是否仍然像undef_t定义的那样有效并且具有正确的对齐方式?
我认为类型是否不完整没有任何区别。
根据 C11 6.2.5.22,只有三种不完整类型可以实例化:
此外,根据 C11 6.2.5.28:
所有指向结构类型的指针应具有相同的表示和对齐要求。所有指向联合类型的指针应具有相同的表示和对齐要求。
因此,无论类型是否完整,指向结构或联合的指针的表示和对齐要求都是已知的,因为您仍然知道它是指向某种结构或联合的指针。
对于数组,因为我们从 C11 6.3.2.1.3 知道:
类型为“类型数组”的表达式将转换为类型为“类型指针”的表达式,该类型指向数组对象的初始元素
那么我们可以得出结论,指向 的指针int和指向 的数组的指针int必须具有相同的对齐要求,因为您可以使用其中任何一个来引用同一个对象。换句话说,所有指向数组的指针都int具有相同的对齐要求,无论大小是否已知。
因此,如果您知道有一个指向结构的指针,或者您知道有一个指向联合的指针,或者您知道有一个指向指定类型的数组的指针,那么您就知道对齐要求是什么。类型不完整这一事实并不重要。事实上,如果这不是真的,那么不完整的类型将没有用处,因为您永远无法可靠地使用指向它们的指针。
在您的情况下, 和undef_t都other_t位于翻译单元中的某个位置typedef,因此您知道您拥有哪种不完整类型,因此您知道它的对齐要求,因此不会因类型不完整而产生歧义。当然,如果您作为程序员使用它们而不费力地自己找出这一点,那么您仍然可能会遇到问题,例如,如果是指向联合的指针,并且是指向结构的指针。但这只是在可能具有不同对齐要求的指针之间进行转换的正常问题 - 这个问题并没有因为多个指向类型之一不完整而变得更加困难。other_tundef_t
编辑 - 根据评论进行一些进一步的说明:
“指向不完整类型的指针”只能指向完整类型的对象,因为根据定义,不完整类型显然无法实例化(为了简洁起见,我忽略了使用malloc()任意数量的内存和指向它的不完整类型的指针)。
存在指向不完整类型的指针是为了能够拥有并传递指向聚合和复合类型的指针,而无需提供可用的类型定义。换句话说,当您没有足够的信息来实例化特定类型,但您确实有足够的信息来指向一个类型时。不透明类型在此基础上工作,所有实际工作都是在类型定义可用的函数中完成的,并且使用这些类型的代码只需要能够存储对象的地址,以便可以将其传递给或从这些功能。
在对齐方面,指针的表示可以根据其指向的对象的对齐要求而改变。例如,正如注释中所指出的,如果所有ints 必须存储在 8 字节边界上,则指针表示形式可能不会存储 3 个最低有效位,因为它们始终为零。但是,如果您随后尝试将指针转换char为int指针并返回,则可能会丢失信息,因为char指针必须能够指向各个字节,并且在假设的到int *.
类似地,可能存在这样的情况:一些小结构可以在 4 字节边界上对齐,而较大的结构可以在 32 字节边界上对齐。但是,由于这些指向不完整类型的指针,结构体指针的对齐要求必须全部相同。在使用指向不完整结构类型的指针的地方,您没有可用的类型定义(如果有,它将是一个完整类型),因此您不知道是否可以忽略最不重要的部分例如,5 位,或仅最低有效位 3 位。因此,指向不完整结构类型的指针的对齐要求必须足够宽松,以便它们可以正确保存任何可想象的结构类型的位置。为了使传递这些更容易,我们可以从上面的引用中看到,C 要求所有指向结构类型的指针具有相同的对齐要求。例如,某些结构实际上可能仍然在 32 字节边界上对齐,但不允许指向该结构的指针充分利用这一点,并且它必须能够保存任何结构类型的位置。
但是,例如,如果所有结构类型在不小于 4 字节边界上对齐,那么对于指向结构的指针(包括指向不完整结构类型的指针)来说,忽略最低有效 3 位是完全可以的,因为您可以在仍然确保您可以安全地表示任何结构的位置。事实上,C 要求所有指向结构类型的指针具有相同的对齐要求,并要求所有指向联合类型的指针具有相同的对齐要求,但不要求指向结构类型的指针的对齐要求与对齐相同对指向联合类型的指针的要求表明,指向结构的指针可能依赖于最小 4 字节边界,但指向联合的指针可能依赖于最小 8 字节边界。在这种情况下,您无法安全地将指向不完整结构类型的指针转换为指向不完整联合类型的指针,然后再转换回来。
这就是为什么像当前另一个答案那样说“不完整类型没有对齐要求”是不正确的。但这确实意味着不完整类型对于原始问题来说不是问题,因为正如已经解释的那样,当你有一个不完整类型时,你至少知道它是结构体、联合体还是数组,这就是你所需要的全部完全了解对齐要求。
| 归档时间: |
|
| 查看次数: |
523 次 |
| 最近记录: |