【问题标题】:cast content of array into arithmetic type in C将数组的内容转换为C中的算术类型
【发布时间】:2012-02-14 10:32:07
【问题描述】:

我正面临着将数组中的单个项目转换为单个算术类型的奇怪行为。

这是一个简化的测试用例:

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 标准中找不到任何东西,但也许我只是个盲人。

您是否知道在没有这种强制转换的情况下执行此操作的任何替代方法(不意味着循环字节到字节的复制/展开等!)并且我不需要知道平台的当前字节顺序?

谢谢!

【问题讨论】:

    标签: c pointers casting access-violation dereference


    【解决方案1】:
     *((unsigned short *)(&test2[1]))
    

    这是未定义的行为,您违反了对齐和别名规则。不要这样做。

    您的test2 对象是unsigned char 的数组,并且通过强制转换,您可以将其元素作为unsigned short 对象访问。不保证unsigned char 对齐要求与unsigned short 对齐要求相同。

    在 C 标准中,您可以找到 6.3.2.3p7 (C99) 中的对齐信息和 6.5p7 中的别名规则。

    一个好的经验法则是在= 运算符左侧出现强制转换时始终保持警惕。

    【讨论】:

    • 谨慎,当然,但有时你确实需要做一些奇怪的事情,C 允许你这样做是件好事。虽然我通常更喜欢 unions 来处理这类事情,但它比指针转换更清洁。
    【解决方案2】:

    这里的问题几乎可以肯定是您正在进行未对齐的访问。如果 chars 是 1 个字节,而 shorts 是 2(很可能),那么您正在对奇数执行 write-short 操作。这并不总是受支持,这就是您最有可能遇到访问冲突的原因。如果你真的想这样做(你可能不这样做),你可以通过在前面增加一个字符来填充 char 数组,然后不使用第一个字符(将数组视为 1 索引而不是 0 -indexed) 并且这可能会在不这样做的平台上工作,但即使这样也不能保证。

    【讨论】:

    • 是的,这可能是个问题。但是您可以使用#pragma pack 来解决这个问题,编译器会将chars 对齐在2 字节边界上。
    • @cha0site: 我认为#pragma pack 只对结构元素打包有影响——它不适用于这种情况,我们有一个数组
    • @PaulR:看来你是对的。但是attribute aligned GCC 扩展确实允许您对齐数组。
    • @cha0site: 是的,但是对齐属性只适用于数组的start(即第一个元素)。如果您尝试访问 char 数组的第三个元素,就好像它是更广泛的类型(例如 int),那么这将总是错位,这可能会也可能不会导致硬件异常。
    • @PaulR:你确定?文档将其描述为union { int i; double d; } x[ARRAY_SIZE]; 的含糖替代品,我很确定它将数组的每个元素与sizeof(double) 边界对齐。
    【解决方案3】:

    *((unsigned long *)(&amp;test[3])) = i; 行具有未定义的行为。这取决于 sizeof(long) 和机器的字节序。 一般来说,你不应该在不同的指针类型之间进行转换(void* 除外)。

    【讨论】:

      猜你喜欢
      • 2014-08-22
      • 2016-10-29
      • 1970-01-01
      • 2021-02-14
      • 2015-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多