是否强制转换为仅包含char []并从该数组读取的结构良好定义的结构?

时间:2019-07-17 00:00:11

标签: c++ strict-aliasing type-punning

reinterpret_cast有许多用途可以编译,但都是UB。仅在少数情况下定义良好。目前对我来说很重要的对象正在转换为:

  • 在其元素或非静态数据成员(包括递归地包括子聚合或所包含的并集的元素或非静态数据成员)中包括上述类型之一的集合或联合类型
  • 字符或无符号字符类型

说我有一个缓冲区,其中包含我要解析的二进制结构。我使用的struct仅包含char a[100],并使用方法来提取位于uint32_t的{​​{1}}。是否将缓冲区强制转换为结构,然后以这种方式良好地访问结构的数组?

如果是这样,我希望是因为上面的两个规则;但是,我也半信半疑这些规则不适用于a[3],或者我可能会遇到某种对齐问题,因为它是一个数组,而不仅仅是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[100],但是通过给char *a设置要解析的结构的大小,可以做到以下几点:好吧:

Overlay

保存一些代码行。


编辑:

多亏了答案和评论,我很清楚Overlay overlay; // fill overlay by writing into it directly std::cout << overlay.parseSomeField() << std::endl; 的这种用法是UB。以下支持使用现有缓冲区并将其直接复制到结构中。您也可以执行reinterpret_cast,这很好。另外,这应该定义清楚:

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; } 及其兄弟姐妹将简单地调用其静态副本,并将其传递给内部缓冲区。

1 个答案:

答案 0 :(得分:2)

  

是否要强制转换为仅由char []组成的结构并从定义良好的数组中读取?

根据以下规则定义不明确:

  

[basic.lval]

     

如果程序试图通过glvalue访问对象的存储值,该glvalue的类型与以下一种类型不相似([conv.qual]),则行为未定义:

     
      
  • 对象的动态类型,
  •   
  • 一种类型,它是与对象的动态类型相对应的有符号或无符号类型,或者
  •   
  • char,unsigned char或std :: byte类型。
  •   

当基础对象是#include "stdafx.h" #include <iostream> using namespace std; int squared(int input); bool pythagCheck(int a, int b, int c); bool repetitionCheck(int a, int b, int c); int x; int increment; int storeA[1000]; int storeB[1000]; int storeC[1000]; int main() { int a = 0, b = 0, c = 0; //input cout << "Specify Boundary: "; cin >> x; cout << "\n\n"; //function for (a=0; a<=x; a++) { if (pythagCheck(a, b, c) && repetitionCheck(a, b, c)) { increment++; storeA[increment] = a; storeB[increment] = b; storeC[increment] = c; } for (b=0; b<=x; b++) { if (pythagCheck(a, b, c) && repetitionCheck(a, b, c)) { increment++; storeA[increment] = a; storeB[increment] = b; storeC[increment] = c; } for (c=0; c<=x; c++) { if (pythagCheck(a, b, c) && repetitionCheck(a, b, c)) { increment++; storeA[increment] = a; storeB[increment] = b; storeC[increment] = c; } } } } system("pause"); return 0; } int squared(int input) { return input * input; } bool pythagCheck(int a, int b, int c) { if (squared(a) + squared(b) == squared(c) && a != 0 && b != 0 && c != 0) { cout << "a = " << a << ", b = " << b << ", c = " << c << endl; return true; } } bool repetitionCheck(int a, int b, int c) { for (int i = 0; i >= increment; i++) { if (storeA[i] == b) { return false; } } for (int i = 0; i >= increment; i++) { if (storeC[i] == c) { return false; } } return true; } 的动态数组时,这些列出的类型都不是Overlay


在这里看起来很明智的解决方案只是一个免费的(或静态成员)函数:

char

您可以使用它来解析向量:

std::uint32_t
parseSomeField(const char* a) const {
    return my_char_to_uint32_t_function(a + 3);
}

或者,如果您的班级类似于parseSomeField(buffer->data());

Overlay