在 C 中将数组内容转换为算术类型
我面临着奇怪的行为,将数组中的单个项目转换为单个算术类型(或者更进一步取消引用)。
这是一个简化的测试用例:
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 标准中找不到任何东西,但也许我只是盲目的。
您是否知道在没有此类转换的情况下执行此操作的任何替代方案(不是循环字节到字节复制/展开等!)以及我不需要知道平台的当前字节顺序的地方?
谢谢!
I'm facing weird behavior with casting (or more even dereferencing) single items from array into a single arithmetic type.
Heres a reduced test case:
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]);
}
}
In detail it is mainly this expression:
*((unsigned short *)(&test2[1]))
I'm getting access violations on some other platforms (mainly embedded platforms like PIC24).
So my question is: is this C conformant? I can't find anything within C-standard but maybe I'm only blind.
Do you know any alternatives doing this operation without such cast (looping byte-to-byte copy/unrolling etc. is not meant!) and where I don't need to know the current byte order of the platform?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是未定义的行为,您违反了对齐和别名规则。不要这样做。
您的
test2
对象是一个unsigned char
数组,通过强制转换,您可以将其元素作为unsigned Short
对象访问。无法保证unsigned char
对齐要求与unsigned Short
对齐要求相同。在 C 标准中,您可以在 6.3.2.3p7 (C99) 中找到有关对齐的信息,在 6.5p7 中找到有关别名规则的信息。
一个好的经验法则是始终非常警惕
=
运算符左侧存在的强制转换。This is undefined behavior, you are violating alignment and aliasing rules. Don't do it.
Your
test2
object is an array ofunsigned char
and through the cast you are accessing its elements asunsigned short
objects. There is no guarantee thatunsigned char
alignment requirement is the same asunsigned short
alignment requirement.In the C standard you can find information on alignment in 6.3.2.3p7 (C99) and on aliasing rules in 6.5p7.
A good rule of thumb is to always be very wary in presence of casts in the left side of the
=
operator.*((unsigned long *)(&test[3])) = i;
行具有未定义的行为。这取决于 sizeof(long) 和机器的字节序。一般来说,您不应该在不同的指针类型之间进行转换(
void*
除外)。The line
*((unsigned long *)(&test[3])) = i;
has undefined behavior. it depends on sizeof(long) and the endianness of your machine.In general, you should not cast between different pointer types (except of
void*
).这里的问题几乎可以肯定是您正在进行未对齐的访问。如果 chars 为 1 个字节,shorts 为 2 个字节(这很可能),那么您正在对奇数执行写短操作。这并不总是受支持,这也是您最有可能遇到访问冲突的原因。如果你真的想这样做(你可能不想),你可以通过在前面加长一个字符来填充字符数组,然后不使用第一个字符(将数组视为 1 索引而不是 0 -indexed),这可能会在不支持的平台上工作,但即使这样也不能保证。
The problem here is almost certainly that you're doing unaligned access. If chars are 1 byte and shorts are 2 (which is likely), then you're doing a write-short operation on an odd number. This is not always supported and is why you're most likely getting an access violation. If you really want to do this (which you probably don't), you could pad the char array by making it one char longer at the front and then just not use that first char (treat the array as 1-indexed rather than 0-indexed) and that would probably work on the platforms where this doesn't, but even that's not guaranteed.