在C语言开发的过程中,发现不同硬件平台出现了一定差异性,例如在x86_64运行正常,二在xlp运行失败,分析如下。
x86_64是小端序,而xlp是大端序。
排查代码的时候,发现在相应申请内存的地方出现了强制转换。
简化原来的代码如下:
DWORD FUNC_A(ULONG *pulMemSize)
{
dwRet = FUNC_B ( (DWORD *)pulMemSize);
return 0;
}
其中DWORD为宏定义的unsigned int,而ULONG为unsigned long。由于FUNC_B为一个静态库提供的接口,同时入参为DWORD类型的指针。因此在这个地方进行了强制的转换。因为从ULOGN指针转换为DWORD指针,因此转换之后的DWORD指针的范围为pulMemSize这个指针所指向内存地址的前四个字节。
来看一下变量内容是如何存储的。
在小端序的系统(x86_64)中,如果*pulMemSize = ABCDEFGH,那么内存的存储顺序为HGFEDCBA(低地址存储变量低位),因此在进行指针转换的时候DWORD指针取值为HGFE,也就是说在 FUNC_B中对pulMemSize所指变量的操作是基于HGFE所在的内存空间,而由于HGFE所在的内存空间在小端序的系统中所表示的恰恰也是pulMemSize所指向变量的低位部分,因此这样操作是没有问题的(前提是取值没有超过32位大小)。
但是在大端序的系统中,pulMemSize所指向变量的存储顺序为ABCDEFGH,而FUNC_B对pulMemSize所指变量的操作则是基于ABCD所在的内存空间,但是ABCD所表示的是pulMemSize所指向变量的高位部分。因此最后在以ULONG来取pulMemSize表示的内存值的时候,则会出错。
更新之后的代码为:
DWORD FUNC_A(ULONG *pulMemSize)
{
DWORD dwMemSize = 0;
dwRet = FUNC_B ( &dwMemSize);
*pulMemSize = (ULONG)dwMemSize;
return 0;
}
可以看出这个dwMemSize这个中间临时变量作用大大的,因此以后如果见到这种看似没有的中间变量,不要轻易删除。
其实这个问题说明的一个问题是,正常变量的强制转换。不同的硬件平台会自动的补齐或者截断对应的高位数据,但是对于指针的操作,由于指针总是从变量起始的位置开始寻址,因此要千万注意指针的强制转换。在不同的硬件系统可能会产生差异性。
本文为CSDN村中少年原创文章,转载记得加上小尾巴偶,博主链接这里。