将指针作为参数传递给从属 dll 错误的对象大小
Passing pointer as argument to slave dll wrong size of object
我有两个模块。一个调用另一个并将结构作为参数传递。
struct {
char* szDGRTag;
bool bTagEx;
} ADPTAG;
Master 是在 Visual C++ 6.0 的 98 年用 C++ 编写的。 Slave 在 Visual Studio 2010 Professional 中用 C++ 11 编写。
在 Slave 中调用的函数:
long lCheckPresenceOfFields (char* szName, ADPTAG* AdpTagList, long lNbVar)
硕士:
long lNbVar = 2;
ADPTAG* AdpTagList = NULL;
AdpTagList = new ADPTAG[lNbVar];
AdpTagList[0].szTag = new char[32];
AdpTagList[0].bTagEx = true;
memset(AdpTagList[0].szTag, 0x0, 32+1);
AdpTagList[0].szTag = NULL;
AdpTagList[1].szTag = new char[32];
AdpTagList[1].bTagEx = true;
memset(AdpTagList[1].szTag, 0x0, 32+1);
AdpTagList[1].szTag = NULL;
int size = sizeof(AdpTagList[0]);
AdpTagList[0].szTag = "DDD";
AdpTagList[1].szTag = "AAA";
long pres = pGetFieldsPresence(szPath, AdpTagList, 2);
我检查过 AdpTagList[0] 在 Master 中的大小,它是 5 个字节,但在 Slave 中是 8 个字节,所以第一个对象是好的,但任何下一个都是坏的,因为指针指向错误的内存面积
这可能是什么问题?不同的编译器?可能不是只有 char* 和 int 的结构在这两个模块之间工作正常。
无论第一个对象 [0] 的大小如何,第二个 [1] 都是空指针。
是的,应该归咎于编译器的差异。在二进制级别,C++ 根本没有标准化。特别是这意味着任何编译器都可以自由选择自己的结构填充规则,这就是影响你的地方。显然,较新的编译器已决定添加 3 个字节的填充以使结构 64 位对齐,但较旧的编译器不会这样做。
一般而言,无法确保两个不同编译器生成的数据之间的二进制兼容性。您可以切换到使用字节流,或者对两者使用相同的编译器。
您 运行 包装不符。您可以使用 "/Zp" compiler option.
修改包装
因为默认 Visual Studio:
Packs structures on 8-byte boundaries
很可能您的 Visual Studio 2010 编译器没有指定打包。您的 Visual C++ 6.0 应用程序可能确实将 1 字节打包指定为包含 int
的结构,并且 char
应该打包到其中。
使用 1 字节打包优化程序系统内存占用,因为没有内存因填充而丢失。
使用 8 字节打包优化速度,因为它增加了在单次加载中获取结构的机会。
有关包装的更多信息,您可以在此处阅读:https://msdn.microsoft.com/en-us/library/71kf49f1.aspx
但我同意微软的声明:
You should not use this option unless you have specific alignment requirements
意思是因为你必须改变一个,我建议改变 Visual C++ 6.0 应用程序上的包装。
我有两个模块。一个调用另一个并将结构作为参数传递。
struct {
char* szDGRTag;
bool bTagEx;
} ADPTAG;
Master 是在 Visual C++ 6.0 的 98 年用 C++ 编写的。 Slave 在 Visual Studio 2010 Professional 中用 C++ 11 编写。
在 Slave 中调用的函数:
long lCheckPresenceOfFields (char* szName, ADPTAG* AdpTagList, long lNbVar)
硕士:
long lNbVar = 2;
ADPTAG* AdpTagList = NULL;
AdpTagList = new ADPTAG[lNbVar];
AdpTagList[0].szTag = new char[32];
AdpTagList[0].bTagEx = true;
memset(AdpTagList[0].szTag, 0x0, 32+1);
AdpTagList[0].szTag = NULL;
AdpTagList[1].szTag = new char[32];
AdpTagList[1].bTagEx = true;
memset(AdpTagList[1].szTag, 0x0, 32+1);
AdpTagList[1].szTag = NULL;
int size = sizeof(AdpTagList[0]);
AdpTagList[0].szTag = "DDD";
AdpTagList[1].szTag = "AAA";
long pres = pGetFieldsPresence(szPath, AdpTagList, 2);
我检查过 AdpTagList[0] 在 Master 中的大小,它是 5 个字节,但在 Slave 中是 8 个字节,所以第一个对象是好的,但任何下一个都是坏的,因为指针指向错误的内存面积
这可能是什么问题?不同的编译器?可能不是只有 char* 和 int 的结构在这两个模块之间工作正常。
无论第一个对象 [0] 的大小如何,第二个 [1] 都是空指针。
是的,应该归咎于编译器的差异。在二进制级别,C++ 根本没有标准化。特别是这意味着任何编译器都可以自由选择自己的结构填充规则,这就是影响你的地方。显然,较新的编译器已决定添加 3 个字节的填充以使结构 64 位对齐,但较旧的编译器不会这样做。
一般而言,无法确保两个不同编译器生成的数据之间的二进制兼容性。您可以切换到使用字节流,或者对两者使用相同的编译器。
您 运行 包装不符。您可以使用 "/Zp" compiler option.
修改包装因为默认 Visual Studio:
Packs structures on 8-byte boundaries
很可能您的 Visual Studio 2010 编译器没有指定打包。您的 Visual C++ 6.0 应用程序可能确实将 1 字节打包指定为包含 int
的结构,并且 char
应该打包到其中。
使用 1 字节打包优化程序系统内存占用,因为没有内存因填充而丢失。
使用 8 字节打包优化速度,因为它增加了在单次加载中获取结构的机会。
有关包装的更多信息,您可以在此处阅读:https://msdn.microsoft.com/en-us/library/71kf49f1.aspx
但我同意微软的声明:
You should not use this option unless you have specific alignment requirements
意思是因为你必须改变一个,我建议改变 Visual C++ 6.0 应用程序上的包装。