C++ 严格别名:这不是 MSFT 示例 UB 吗? [复制]

Posted

技术标签:

【中文标题】C++ 严格别名:这不是 MSFT 示例 UB 吗? [复制]【英文标题】:C++ strict aliasing: Isn't this MSFT example UB? [duplicate] 【发布时间】:2017-06-29 03:45:35 【问题描述】:

在关于某个 Winsock 结构的this 页面上,该示例似乎正在获取结构的地址并将结果指针转换为指向完全不同结构的指针。

SOCKET ListenSocket;
struct sockaddr_in saServer;
// Bind the listening socket using the information in the sockaddr structure
bind( ListenSocket,(SOCKADDR*) &saServer, sizeof(saServer) );

这是两个结构的声明。这是技术上未定义的行为,对吗?

struct sockaddr 
        ushort  sa_family;
        char    sa_data[14];
;

struct sockaddr_in 
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
;

【问题讨论】:

指针转换从不违反严格的别名规则(似乎这是一个常见的误解) @M.M,但是bind 的实现肯定必须遵守那个指针,并且在 那个 点你违反了严格的别名规则,不是吗? (我有一个模糊的印象,您可能会因为通过别名读取的结构的唯一元素位于结构的开头并且对两者都通用,但对我来说一点也不明显从语言律师的角度来看确实如此。) @HarryJohnston 库实现不受 ISO C++ 规则的约束,它们甚至可能不是用 C++ 编写的 @MM,很公平;这解决了这个特定上下文中的问题。我想如果你自己实现bind,你可以通过将指针显式转换为shortas discussed here来保证它的安全。我不确定这是否必要,但应该足够了。 【参考方案1】:

在 C 语言的诞生(至少可以追溯到 1974 年)和 1989 年之间,如果两个结构共享一个通用初始序列,则该语言明确允许代码使用一种结构类型的指针来检查另一种结构类型的 CIS 成员。在 C99 标准中,该权限仅限于两种结构类型都是联合类型的一部分的情况,该联合类型的完整 声明 在检查 CIS 值时可见;有些人坚持认为,因为 1989 的作者打算施加这样的限制,所以它也适用于 C89。此外,一些编译器作者坚持认为,因为标准的作者只是为了保证该保证适用于通过联合类型的左值进行的访问,他们将忽略标准中说“完整联合type" 必须可见。

允许实现提供超出标准要求的保证。因为在 C99 之前编写代码的非通灵者没有理由期望他们需要包含其他不必要的联合声明以利用 CIS 保证,并且因为那个时代编写的许多代码都依赖于这些保证,尽管缺少此类声明,任何想要编写适合与此类代码一起使用的实现的人都必须支持它们无论标准是否需要此类支持。虽然没有特别好的理由说明头文件的更新不应该包含联合类型声明,但我不确定有多少编译器会关心它的存在与否。我见过的编译器要么支持 CIS 保证,即使没有完整的联合类型声明可见,或者即使声明存在也不尊重 CIS 保证(忽略标准)。

【讨论】:

以上是关于C++ 严格别名:这不是 MSFT 示例 UB 吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

这真的违反了严格的别名规则吗?

这真的违反了严格的别名规则吗?

c++ 模板化抽象基类数组,不违反严格别名规则

C++ 构建警告:取消引用类型双关指针将破坏严格别名规则

C++ 中的简单存储类和严格的别名

线程示例,分段错误