是否转换为仅由 char[] 组成的结构并从定义明确的数组中读取?
Is casting to a struct that consists solely of a char[] and reading from that array well defined?
reinterpret_cast
有很多用途可以编译,但都是 UB。它仅在少数情况下得到明确定义。目前对我来说很重要的是:
- 在其元素或非静态数据成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的元素或非静态数据成员)
- char 或 unsigned char 类型
假设我有一个缓冲区,其中包含我要解析的二进制结构。我使用仅包含 char a[100]
的 struct
并使用方法来提取位于 a[3]
的 uint32_t
。是否将缓冲区转换为结构,然后以这种方式访问结构的数组?
如果是,我想那是因为上面的两条规则;但是,我也有一半希望这些规则不适用于 char[]
,或者我可能会遇到某种对齐问题,因为它是一个数组而不仅仅是 char*
。
使用例更清晰的小代码示例:
struct Overlay {
char a[100];
uint32_t parseSomeField() const {
return my_char_to_uint32_t_function(&a[3]);
}
};
int main() {
std::vector<char> buffer(1024);
// fill buffer
auto overlay = reinterpret_cast<const Overlay*>(&buffer[0]);
std::cout << overlay->parseSomeField() << std::endl;
}
我假设用简单的 char *a
替换 char a[100]
肯定没问题,但是通过给 Overlay
我想要解析的结构的大小,它允许我做还有以下内容:
Overlay overlay;
// fill overlay by writing into it directly
std::cout << overlay.parseSomeField() << std::endl;
节省了一些代码行。
编辑:
感谢回答和评论,我很清楚 reinterpret_cast
的这种用法是 UB。以下支持使用现有缓冲区 和 直接复制到结构中。你也可以做 sizeof
,这很好。此外,这应该明确定义:
struct VersatileOverlay {
char a[100];
static uint32_t parseSomeField(const char *a) {
return some_char_to_uint32_t_function(a + 3);
}
uint32_t parseSomeField() const {
return parseSomeField(&a[0]);
}
};
int main() {
std::vector<char> buffer(1024);
// fill buffer
std::cout << VersatileOverlay::parseSomeField(&buffer[0]) << std::endl;
VersatileOverlay vo;
memcpy(&vo, /*source ptr*/, sizeof(VersatileOverlay));
std::cout << vo.parseSomeField() << std::endl;
}
parseSomeField()
及其兄弟姐妹将简单地调用它们的静态对象,将它们传递给内部缓冲区。
Is casting to a struct that consists solely of a char[] and reading from that array well defined?
根据以下规则,它不是 well-defined:
[basic.lval]
If a program attempts to access the stored value of an object through a glvalue whose type is not similar ([conv.qual]) to one of the following types the behavior is undefined:
- the dynamic type of the object,
- a type that is the signed or unsigned type corresponding to the dynamic type of the object, or
- a char, unsigned char, or std::byte type.
None 这些列出的类型是 Overlay
,当基础对象是 char
.
的动态数组时
这里看起来像是一个明智的解决方案,只是一个免费(或静态成员)函数:
std::uint32_t
parseSomeField(const char* a) const {
return my_char_to_uint32_t_function(a + 3);
}
你可以用它来解析一个向量:
parseSomeField(buffer->data());
或者,如果您确实有一个类似于 Overlay
的 class:
parseSomeField(overlay.a);
reinterpret_cast
有很多用途可以编译,但都是 UB。它仅在少数情况下得到明确定义。目前对我来说很重要的是:
- 在其元素或非静态数据成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的元素或非静态数据成员)
- char 或 unsigned char 类型
假设我有一个缓冲区,其中包含我要解析的二进制结构。我使用仅包含 char a[100]
的 struct
并使用方法来提取位于 a[3]
的 uint32_t
。是否将缓冲区转换为结构,然后以这种方式访问结构的数组?
如果是,我想那是因为上面的两条规则;但是,我也有一半希望这些规则不适用于 char[]
,或者我可能会遇到某种对齐问题,因为它是一个数组而不仅仅是 char*
。
使用例更清晰的小代码示例:
struct Overlay {
char a[100];
uint32_t parseSomeField() const {
return my_char_to_uint32_t_function(&a[3]);
}
};
int main() {
std::vector<char> buffer(1024);
// fill buffer
auto overlay = reinterpret_cast<const Overlay*>(&buffer[0]);
std::cout << overlay->parseSomeField() << std::endl;
}
我假设用简单的 char *a
替换 char a[100]
肯定没问题,但是通过给 Overlay
我想要解析的结构的大小,它允许我做还有以下内容:
Overlay overlay;
// fill overlay by writing into it directly
std::cout << overlay.parseSomeField() << std::endl;
节省了一些代码行。
编辑:
感谢回答和评论,我很清楚 reinterpret_cast
的这种用法是 UB。以下支持使用现有缓冲区 和 直接复制到结构中。你也可以做 sizeof
,这很好。此外,这应该明确定义:
struct VersatileOverlay {
char a[100];
static uint32_t parseSomeField(const char *a) {
return some_char_to_uint32_t_function(a + 3);
}
uint32_t parseSomeField() const {
return parseSomeField(&a[0]);
}
};
int main() {
std::vector<char> buffer(1024);
// fill buffer
std::cout << VersatileOverlay::parseSomeField(&buffer[0]) << std::endl;
VersatileOverlay vo;
memcpy(&vo, /*source ptr*/, sizeof(VersatileOverlay));
std::cout << vo.parseSomeField() << std::endl;
}
parseSomeField()
及其兄弟姐妹将简单地调用它们的静态对象,将它们传递给内部缓冲区。
Is casting to a struct that consists solely of a char[] and reading from that array well defined?
根据以下规则,它不是 well-defined:
[basic.lval]
If a program attempts to access the stored value of an object through a glvalue whose type is not similar ([conv.qual]) to one of the following types the behavior is undefined:
- the dynamic type of the object,
- a type that is the signed or unsigned type corresponding to the dynamic type of the object, or
- a char, unsigned char, or std::byte type.
None 这些列出的类型是 Overlay
,当基础对象是 char
.
这里看起来像是一个明智的解决方案,只是一个免费(或静态成员)函数:
std::uint32_t
parseSomeField(const char* a) const {
return my_char_to_uint32_t_function(a + 3);
}
你可以用它来解析一个向量:
parseSomeField(buffer->data());
或者,如果您确实有一个类似于 Overlay
的 class:
parseSomeField(overlay.a);