让我们考虑以下(简化)代码来读取二进制文件的内容:
struct Header
{
char signature[8];
uint32_t version;
uint32_t numberOfSomeChunks;
uint32_t numberOfSomeOtherChunks;
};
void readFile(std::istream& stream)
{
// find total size of the file, in bytes:
stream.seekg(0, std::ios::end);
const std::size_t totalSize = stream.tellg();
// allocate enough memory and read entire file
std::unique_ptr<std::byte[]> fileBuf = std::make_unique<std::byte[]>(totalSize);
stream.seekg(0);
stream.read(reinterpret_cast<char*>(fileBuf.get()), totalSize);
// get the header and do something with it:
const Header* hdr = reinterpret_cast<const Header*>(fileBuf.get());
if(hdr->version != expectedVersion) // <- Potential UB?
{
// report the error
}
// and so on...
}
在我看来,下面一行:
if(hdr->version != expectedVersion) // <- Potential UB?
包含未定义的行为:我们正在读取uint32_t
类型的version
成员,它覆盖在std::byte
对象的数组之上,并且编译器可以自由地假设uint32_t
对象不别名。
问题是:我的解释正确吗?如果是,可以做什么来修复此代码?如果没有,为什么这里没有UB?
注1:我理解严格别名规则的目的(允许编译器避免不必要的内存加载)。此外,我知道在这种情况下,使用<code>std::memcpy</code>是一个安全的解决方案,但使用<code>std::memcpi</code>意味着我们必须进行额外的内存分配(在堆栈上,或者在堆上,如果对象的大小未知)。
如何修复这段代码?
等待,直到http://wg21.link/P0593或者类似的允许在<code>char</code>/<code>unsigned char</code>/<code>std::byte</code>的数组中创建隐式对象的方法。
问题是:我的解释正确吗?
对
如果是,可以做些什么来修复此代码?
您已经知道 memcpy 是一种解决方案。但是,您可以通过直接读取标头对象来跳过 memcpy 和额外的内存分配:
Header h;
stream.read(reinterpret_cast<char*>(&h), sizeof h);
注意,以这种方式读取二进制文件意味着文件的整数表示必须与CPU的表示相匹配。这意味着该文件不能移植到具有不同CPU体系结构的系统。
这是一个典型的严格混叠违规示例: 但假设我们添加第二: 这段代码正确吗(不调用未定义的行为)? 标准[expr.reinterpret.cast]如下: 注意:将“指针到<code>T1</code>”类型的prvalue转换为“指针到 和<code>T2是对象类型,并且<code>T2的对齐要求不比<code>T 1 我们使用 类型的原始指针值来访问 类型。 当优化打开时,GCC和Clang都会
我不知道为什么下面的代码运行得很好,没有< code>gcc错误(< code >-f strict-aliasing-Wstrict-aliasing = 1 )。 如果我遵循严格的别名规则: n1570,§6.5表达式 对象的存储值只能由具有以下类型之一的左值表达式访问: -与对象的有效类型兼容的类型, — 与对象的有效类型兼容的类型的限定版本, -与对象的有效类型对应的有符号或无符号类型的类
下面的getValue()成员函数是否违反了c严格别名规则? 根据该标准,我认为setValue()违反了严格的混淆现象,因为Double既不是聚合类型,也不是IEEE754_64的基类。 getValue()呢?当数据成员采用位字段形式时,它是否是一种未定义的行为,如下例所示? 我正在一个大型项目中使用类似的代码。GCC-O2和-O3输出错误值。如果我添加-fno严格的别名,问题就不存在了。此外
在这些注释中,user @Deduplicator坚持认为,如果别名指针或别名指针是指向字符的指针类型(限定或非限定,有符号或无符号< code>char *),则严格的别名规则允许通过不兼容的类型进行访问。所以,他的观点基本上是 和 符合并具有定义的行为。 然而,在我看来,只有第一种形式是有效的,即当别名指针是指向char的指针时;然而,在另一个方向上却不能,即当别名指针指向不兼容的类型(而不是
我和一位同事正试图实现一个简单的多态类层次结构。我们正在开发嵌入式系统,并且仅限于使用C编译器。我们有一个基本的设计理念,可以在没有警告的情况下编译(-Wall -Wextra -fstrict-aliasing -pedantic),并且在gcc 4.8.1下运行良好。 然而,我们有点担心别名问题,因为我们并不完全了解这何时会成为一个问题。 为了演示,我们编写了一个带有“接口”IHello和两个
当违反严格的混淆现象规则时,我试图掌握未定义的行为。为了理解它,我读了很多关于SO的文章。然而,还有一个问题:我并不真正理解两种类型的非法别名。cpp-参考指出: 类型混淆现象 每当尝试通过AliasedType类型的glvalue读取或修改DynamicType类型对象的存储值时,除非以下之一为真,否则行为未定义: AliasedType和DynamicType类似 AliasedType是Dy