在C中将数组内容强制转换为算术类型
我面临着将数组中的单个项强制转换(甚至取消引用)为单个算术类型的奇怪行为 以下是简化的测试用例:在C中将数组内容强制转换为算术类型,c,pointers,casting,access-violation,dereference,C,Pointers,Casting,Access Violation,Dereference,我面临着将数组中的单个项强制转换(甚至取消引用)为单个算术类型的奇怪行为 以下是简化的测试用例: 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
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]);
}
}
我在其他一些平台(主要是嵌入式平台,如PIC24)上遇到访问冲突
所以我的问题是:这是符合C的吗?我在C-standard中找不到任何东西,但也许我只是个盲人
您知道没有这种强制转换(不意味着循环字节到字节的复制/展开等)的情况下执行此操作的其他方法吗?我不需要知道平台的当前字节顺序
谢谢
*((unsigned short *)(&test2[1]))
这是未定义的行为,您违反了对齐和别名规则。不要这样做
您的test2
对象是一个无符号字符的数组
,通过强制转换,您可以作为无符号短
对象访问其元素。不能保证无符号字符
对齐要求与无符号短字符
对齐要求相同
在C标准中,您可以在6.3.2.3p7(C99)中找到有关对齐的信息,并在6.5p7中找到有关别名规则的信息
一个很好的经验法则是,在=
操作符左侧出现强制类型转换时,始终要非常小心 行*((无符号长*)(&test[3]))=i代码>具有未定义的行为。这取决于机器的长度和尺寸。
一般来说,您不应该在不同的指针类型之间强制转换(除了void*
)。这里的问题几乎可以肯定是您正在进行未对齐的访问。如果char是1字节,shorts是2字节(这很可能),那么您正在对奇数执行写短操作。这并不总是受支持的,这也是您最有可能遇到访问冲突的原因。如果您真的想这样做(您可能不想这样做),您可以通过使字符数组的前面长一个字符来填充字符数组,然后不使用第一个字符(将数组视为1索引而不是0索引),这可能会在没有这样做的平台上起作用,但即使这样也不能保证 是的,那可能是个问题。但是你可以用#pragma pack
来修复这个问题,编译器将在2字节边界上对齐字符。@cha0site:我认为#pragma pack
只对结构元素打包有影响-在我们有array@PaulR:看来你是对的。但是GCC扩展允许您对齐数组。@cha0site:是的,但aligned属性仅适用于数组的开头(即第一个元素)。如果您试图访问字符数组的第三个元素,就好像它是一个更广泛的类型,如int,那么它将始终未对齐,这可能会或可能不会导致硬件异常。@PaulR:确定吗?文档将其描述为union{inti;double d;}x[ARRAY_SIZE];的一种甜的替代方案代码>,我很确定它会将数组的每个元素对齐到sizeof(double)
边界。当然要小心,但有时确实需要做一些奇怪的事情,而且C允许你这么做是件好事。虽然我通常更喜欢使用union
s来处理这类事情,但它是一个比指针强制转换更干净的解决方案。
*((unsigned short *)(&test2[1]))