我面临着将数组中的单个项强制转换(甚至取消引用)为单个算术类型的奇怪行为。
下面是一个简化的测试用例:
void test1()
{
unsigned char test[10] = {0};
unsigned long i=0xffffffff;
*((unsigned long *)(&test[3])) = i;
int it;
for ( it = 0 ; it < 10 ; it++ )
{
printf("%02x ", test[it]);
}
}
void test2()
{
unsigned char test[10] = {0};
unsigned char test2[10] = {0};
test[2]=0xFF;
test[3]=0xFF;
*((unsigned short *)(&test2[1])) = *((unsigned short *)(&test[2]));
int it;
for ( it = 0 ; it < 10 ; it++ )
{
printf("%02x ", test2[it]);
}
}
详细来说,主要是这样的表达:
*((unsigned short *)(&test2[1]))
我在其他一些平台(主要是像PIC24这样的嵌入式平台)上遇到了访问违规。
所以我的问题是:这是否符合C?我找不到任何符合C标准的东西,但也许我只是盲人。
你知道在没有这种强制转换的情况下执行此操作的任何替代方案吗(循环字节到字节的复制/展开等不是故意的!)以及在哪里我不需要知道平台的当前字节顺序?
谢谢!
*((unsigned short *)(&test2[1]))
这是未定义的行为,您违反了对齐和别名规则。不要这么做。
您的test2
对象是unsigned char
的数组,通过强制转换,您将访问其元素作为unsigned short
对象。不能保证unsigned char
对准要求与unsigned short
对准要求相同。
在C标准中,您可以在6.3.2.3p7(C99)中找到有关对齐的信息,在6.5p7中找到有关混叠规则的信息。
一个很好的经验法则是,在=
运算符的左侧出现铸造时,始终要非常小心。
行*((unsigned long *)(&test[3])) = i;
具有未定义的行为。它取决于sizeof(long)和机器的字节序。通常,不应在不同的指针类型之间进行强制转换(void*
除外)。
这里的问题几乎可以肯定是您正在进行未对齐的访问。如果字符是1字节,短字符是2(很可能),那么您正在对奇数执行写短操作。这并不总是受支持的,这也是您最有可能遇到访问违规的原因。如果你真的想这样做(你可能不想这样做),你可以通过在前面增加一个字符来填充char数组,然后不使用第一个字符(将数组视为1-索引而不是0-索引),这可能在不这样做的平台上有效,但即使这样也不能保证。