- #pragma pack(push, PPP)
- struct XXX
- {
- LPVOID m_AAA;
- ULONG m_BBB;
- ULONG m_CCC;
- ULONG m_DDD;
- };
- #pragma pack(pop)
Где PPP я установил в 4 для x86 и в 8 для x64. Другими словами каждое поле начинается со смещения кратного размеру указателя. С другой стороны, в CLR, я определил структуру примерно таким образом:
- static mdToken const g_NilImplements[] = {mdTokenNil};
- mdTypeDef stk;
- if (hr = mde->DefineTypeDef(L"XXX", tdNotPublic | tdSequentialLayout | tdClass | tdSealed | tdBeforeFieldInit | tdAnsiClass, valueTypeToken, const_cast<mdToken *>(g_NilImplements), &stk), FAILED(hr))
- throw _hr_error("Can't emit inject structure", hr);
- if (hr = mde->SetClassLayout(stk, PPP, NULL, 0), FAILED(hr))
- throw _hr_error("Can't emit inject structure", hr);
- static BYTE const g_fblobPtr[] =
- {
- IMAGE_CEE_CS_CALLCONV_FIELD,
- ELEMENT_TYPE_PTR, ELEMENT_TYPE_VOID,
- };
- mdFieldToken ftkAAA;
- if (hr = mde->DefineField(stk, L"AAA", fdPublic, g_fblobPtr, sizeof(g_fblobPtr) / sizeof(*g_fblobPtr), ELEMENT_TYPE_END, NULL, 0, &ftkAAA), FAILED(hr))
- throw _hr_error("Can't emit field structure", hr);
- static BYTE const g_fblobUInt32[] =
- {
- IMAGE_CEE_CS_CALLCONV_FIELD,
- ELEMENT_TYPE_U4,
- };
- mdFieldToken ftkBBB;
- if (hr = mde->DefineField(stk, L"BBB", fdPublic, g_fblobUInt32, sizeof(g_fblobUInt32) / sizeof(*g_fblobUInt32), ELEMENT_TYPE_END, NULL, 0, &ftkBBB), FAILED(hr))
- throw _hr_error("Can't emit field structure", hr);
- mdFieldToken ftkCCC;
- if (hr = mde->DefineField(stk, L"CCC", fdPublic, g_fblobUInt32, sizeof(g_fblobUInt32) / sizeof(*g_fblobUInt32), ELEMENT_TYPE_END, NULL, 0, &ftkCCC), FAILED(hr))
- throw _hr_error("Can't emit field structure", hr);
- mdFieldToken ftkDDD;
- if (hr = mde->DefineField(stk, L"DDD", fdPublic, g_fblobUInt32, sizeof(g_fblobUInt32) / sizeof(*g_fblobUInt32), ELEMENT_TYPE_END, NULL, 0, &ftkDDD), FAILED(hr))
- throw _hr_error("Can't emit field structure", hr);
Мир казался прекрасным под x86, но стоило запуститься под x64 структуры кардинально разъехались. После внимательного изучения документации выяснилось, что в CLR в отличии от C/C++ для выравнивания выбирается меньшее из двух чисел: размер самого поля и установленного через SetClassLayout выравнивания. Для устранения проблемы пришлось установить PPP в 1 для всех платформ. Хотя в принципе есть и другие решения, но я выбрал самое простое.

0 коммент.:
Отправить комментарий