从uchar*到uint*的施法会产生不可预测的结果

从uchar*到uint*的施法会产生不可预测的结果,c,arm,C,Arm,我正在使用C99编译这段代码,其中包含一些不同的类型定义,比如uint32,而不是针对旧的arm体系结构的uint32\t uint32 x2 = *((uint32 *) &data[t]); uint32 x3; memcpy(&x3, &data[t], 4); printf("%d %d %d %d %d %d", x2, x3, data[t], data[t + 1], data[t + 2], data[t + 3]); 数

我正在使用C99编译这段代码,其中包含一些不同的类型定义,比如uint32,而不是针对旧的arm体系结构的uint32\t

    uint32 x2 = *((uint32 *) &data[t]);
    uint32 x3;
    memcpy(&x3, &data[t], 4);
    printf("%d %d %d %d %d %d", x2, x3, data[t], data[t + 1], data[t + 2], data[t + 3]);
数据为uchar*且长度>t+4

但令人惊讶的是,结果是:

-268435454 2 2 0 0 0
此铸造有什么问题?

x2线导致未定义的行为。首先,数据[t]可能没有32位对齐,其次,从该位置读取32位值可能是一种严格的别名冲突

只需删除该行并使用x3版本。

x2行会导致未定义的行为。首先,数据[t]可能没有32位对齐,其次,从该位置读取32位值可能是一种严格的别名冲突


只需删除该行,然后使用x3版本。

这里有几个问题。不要使用指针双关,使用联合


您的printf格式也是错误的。您应该使用%u而不是%d

这里有几个问题。不要使用指针双关,使用联合


您的printf格式也是错误的。您应该使用%u而不是%d

正如其他答案所评论的,这个问题来自于一个问题。虽然x64或x86绝对支持未对齐访问,但不能说ARM完全不支持它,因为它依赖于ARM版本。 有三种可能性:

在包含ARMv5之前。ARM不支持未对齐的访问,这就是uint32 x2=*uint32*&数据[t];从LDR的角度来看,32位变量的四个字节中有三个未对齐为4,只有一个对齐,因此结果未定义,因此出现错误。鉴于此,问题必须通过ARM上的软件解决,因为未对齐的指针或结构是有用的。 在包含ARMv7之后,它们确实允许未对齐的访问*,因此代码应该是有效的,没有错误。然而,性能是一个完全不同的主题,我非常确定它将比32位对齐的访问速度慢,但是这个主题值得自己的条目。 ARMv6。通常情况下,手臂有一些使事情变得更有趣的东西,对齐也不会有什么不同。在这里,他们添加的目的是选择您喜欢哪种方式的ARMv5或ARMv7

考虑一个旧的arm体系结构注释,您的案例看起来像第一个,但是如果您包括您的汇编代码和体系结构,这将是一个完整的答案


*一些说明将失败,因为它们无法支持它,即

正如其他答案所评论的,问题来自一个错误。虽然x64或x86绝对支持未对齐访问,但不能说ARM完全不支持它,因为它依赖于ARM版本。 有三种可能性:

在包含ARMv5之前。ARM不支持未对齐的访问,这就是uint32 x2=*uint32*&数据[t];从LDR的角度来看,32位变量的四个字节中有三个未对齐为4,只有一个对齐,因此结果未定义,因此出现错误。鉴于此,问题必须通过ARM上的软件解决,因为未对齐的指针或结构是有用的。 在包含ARMv7之后,它们确实允许未对齐的访问*,因此代码应该是有效的,没有错误。然而,性能是一个完全不同的主题,我非常确定它将比32位对齐的访问速度慢,但是这个主题值得自己的条目。 ARMv6。通常情况下,手臂有一些使事情变得更有趣的东西,对齐也不会有什么不同。在这里,他们添加的目的是选择您喜欢哪种方式的ARMv5或ARMv7

考虑一个旧的arm体系结构注释,您的案例看起来像第一个,但是如果您包括您的汇编代码和体系结构,这将是一个完整的答案


*某些指令将失败,因为它们无法支持它,即

也检查格式说明符-如果int为16位,则使用%d打印uint32会导致未定义的行为。您可能应该写入%lu并将参数显式转换为unsigned long。事实上,最好使用C99指定的标准固定宽度类型uint32,而不是自定义类型uint32,以便使用sizeofx3而不是4。@Hassan uint32是C99的一部分,您说过您正在使用C99。根据ARM版本,可能支持或不支持未对齐访问。在我看来,您应该包括架构。要同时保证endian和对齐的安全性,如果您想做这样的事情,您需要一次构建32位数字8位。独立于底层架构。或者从一个对齐的大小uint32\t开始,例如,如果要提取这些地址的字节,则屏蔽并移出它们,反之,从大到小的成功几率要比从小到大的高很多。请检查格式说明符-如果int为16位,则使用%d打印uint32会导致未定义的行为。您可能应该写入%lu并将参数显式转换为unsigned long。事实上,使用它会更好
C99指定的标准固定宽度类型uint32,而不是自定义类型uint32,以使用sizeofx3而不是4。@Hassan uint32是C99的一部分,您说过您正在使用C99,根据ARM版本的不同,可能支持或不支持未对齐访问。在我看来,您应该包括架构。要同时保证endian和对齐的安全性,如果您想做这样的事情,您需要一次构建32位数字8位。独立于底层架构。或者从对齐的大小uint32\t开始,例如,如果要提取这些地址的字节,则屏蔽并将其移出,而不是相反,从大到小成功的几率要高得多,然后从小到大。数据是uchar*,因此其中没有对齐。此外,如果数据中存在任何对齐,memcpy也应该失败。写入时会发生别名冲突。在本例中,仅从数据中读取数据,但有3种不同的方式。@Hassan是的,数据中没有对齐是问题所在。铸件需要对齐才能正常工作。memcpy不需要任何对齐。读和写都可能发生别名冲突。@Hassan同意没有别名冲突。关于memcpy的分歧也应该失败。memcpy在这里工作正常。@chux你是说原始代码中没有别名冲突吗?如果是这样的话,你就错了,除非数据指向malloc'd空间,它之前的值被写进了uint32,我们从发布的代码中看不出来,我在printf中看到了AA,因为是x3,而不是x2。数据是uchar*因此它内部没有对齐。此外,如果数据中存在任何对齐,memcpy也应该失败。写入时会发生别名冲突。在本例中,仅从数据中读取数据,但有3种不同的方式。@Hassan是的,数据中没有对齐是问题所在。铸件需要对齐才能正常工作。memcpy不需要任何对齐。读和写都可能发生别名冲突。@Hassan同意没有别名冲突。关于memcpy的分歧也应该失败。memcpy在这里工作正常。@chux你是说原始代码中没有别名冲突吗?如果是这样的话,你就错了,除非数据指向malloc'd空间,它之前的值被写入uint32,我们无法从发布的代码中看出这一点。我在printf中看到AA是由于x3,而不是x2。