将数组的内容强制转换为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标准的东西,但也许我只是盲人。

你知道在没有这种强制转换的情况下执行此操作的任何替代方案吗(循环字节到字节的复制/展开等不是故意的!)以及在哪里我不需要知道平台的当前字节顺序?

谢谢!

 *((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-索引),这可能在不这样做的平台上有效,但即使这样也不能保证。

最新更新