【发布时间】:2021-03-08 12:36:48
【问题描述】:
我有一个使用 fread() 将二进制文件读入结构的旧项目。 它使用 Visual Studio 2017 (v141)
我将项目升级到 VS 2019 的最新 C++ 工具版本 (v142),并将解决方案从 AnyCPU 更改为 x86。
我还更改了 Struct Member 对齐方式: 1 字节 (/Zp1) 收件人:默认
因为这个错误:
错误 C2338 Windows 标头需要默认打包选项。 更改此设置可能会导致内存损坏。这个诊断可以 通过定义 WINDOWS_IGNORE_PACKING_MISMATCH 的构建禁用。
但是现在数据不再被正确读取了。
这是我用来读取二进制文件的代码:
FILE* RecipeFile;
short ReturnValue = 0; //AOK
if ((RecipeFile = fopen(rcpFile, "rb")) == NULL) {
ReturnValue = -1; //File open error
return(ReturnValue);
}
long sizeOfItem;
// obtain file size:
fseek(RecipeFile, 0, SEEK_END);
sizeOfItem = ftell(RecipeFile); // gives 771088
rewind(RecipeFile);
//sizeOfItem = sizeof(recipe); // gives 824304??
// now read the file contents:
int noOfItemsRead = fread(&recipe, sizeOfItem, 1, RecipeFile);
recipe 是一个结构。见下文。
我注意到sizeof(recipe) 给出的结果与文件大小不同。
使用工具集 141,我得到 798276 字节。
使用工具集 142,我得到 824304 字节。
实际文件大小为 771088 字节。
这个问题真的是由于结构成员对齐的变化引起的吗?
如何修复错误,以便再次正确读取文件?
编辑: 我尝试将编译指示包指令添加到结构中,如下所示:
#pragma pack(push, 1)
struct tRecipe {
RMPTableDescriptorType O2Flow;
RMPTableDescriptorType HeFlow;
RMPTableDescriptorType SiCl4Flow;
RMPTableDescriptorType GeCl4Flow;
RMPTableDescriptorType Extra_Flow;
RMPTableDescriptorType POCl3Flow;
RMPTableDescriptorType C2F6Flow;
RMPTableDescriptorType SiF4Flow;
RMPTableDescriptorType Cl2Flow;
RMPTableDescriptorType BCl3Flow;
RMPTableDescriptorType TTC_Temp;
RMPTableDescriptorType TTC_H2Flow;
RMPTableDescriptorType TTC_Ratio;
RMPTableDescriptorType LCC_Speed;
RMPTableDescriptorType LSC_Speed;
RMPTableDescriptorType LTC_Speed;
RMPTableDescriptorType TDS_Cursor;
RMPTableDescriptorType TDC_Ctrl;
RMPTableDescriptorType TPC_Ctrl;
RMPTableDescriptorType TSS_Cursor;
DLUTableDescriptorType DLU;
EXHTableDescriptorType EXH;
GENTableDescriptorType GEN;
PARTableDescriptorType PAR;
REFTableDescriptorType REF;
SETTableDescriptorType SET;
SUPTableDescriptorType SUP;
TDCTableDescriptorType TDC;
TDSTableDescriptorType TDS;
TSSTableDescriptorType TSS;
TTCTableDescriptorType TTC;
TPCTableDescriptorType TPC;
};
#pragma pack(pop)
typedef struct
{
RParam Value;
UInt16 Duration;
OptType Opt;
#if DOS
int Unused16BitVar; /* Established to allow Win32 NT Code to use 32bit */
#endif
}
RMPElementDescriptorType;
/*-----------------------------------------------------------------------------*/
typedef struct
{
UInt16 StartNoOf;
UInt16 EndNoOf;
Char8 StartRampType;
Char8 EndRampType;
RMPElementDescriptorType RMPElementArray[RAMP_ELEM_NO_OF];
}
RMPRampDescriptorType;
/*-----------------------------------------------------------------------------*/
typedef struct
{
UInt16 SizeInfo;
Char8 DBPTxtInfo[DBP_TXT_NO_OF];
RMPRampDescriptorType RMPRampArray[RAMP_NO_OF];
}
RMPTableDescriptorType;
但它似乎对错误没有任何影响。
【问题讨论】:
-
你应该把你的结构打包。见stackoverflow.com/questions/1537964/…
-
MSVC 编译器使用
packpragma 即时更改打包。所以你可以在定义之前用#pragma pack(push, 1)和在定义之后用#pragma pack(pop)包围struct recipe的定义。这将使struct recipe以 1 字节对齐方式打包,但其他所有内容都以默认对齐方式打包。见packpragma。 -
您的文件是任何想要读取或写入文件的人的“界面”。它要求打包被明确定义,以便任何人都可以独立于编译器进行读写。
-
"recipe 是一个结构,我不会在此处包含它,因为它非常大。" 您至少应该提供一个省略的版本 - 甚至只是它的名称/标签- 如果使用您的命名,答案会更有意义。
-
我在头文件中添加了#pragma pack(push, 1) 但我仍然没有得到正确的数据...
标签: c++ c visual-studio-2019 struct-member-alignment