繁体   English   中英

在8位平台或32位平台上将uint8_t的元素转换为32位变量

[英]Casting element of uint8_t to 32-bit variable on 8-bit platform or 32-bit platform

让我们考虑两个例子

1:8位MCU / MPU /平台-小端

uint8_t arr[5] = {0x1,0x2,0x3,0x4,0x5};//assume &arr[0] == 0x0
uint32_t *ui32 = (uint32_t*)&arr[1];

*ui32的值是*ui32 0x2030405 是否需要在此平台uint32_t变量放置到4的地址倍数上?

1:32位MCU / MPU /平台-小端

几乎相同的示例:

uint8_t arr[] = {0x1,0x2,0x3,0x4,0x5, 0x6, 0x7, 0x8}; //again assume &arr[0] == 0x0
uint32_t *ui32 = (uint32_t*)&arr[1];

*ui32的值是*ui32

我知道32位变量应该驻留在4的地址倍数中。

在哪里可以找到规范?

语言律师

您的代码包含未定义的行为,并且不可移植。 例如,在我编写过的某些UNIX工作站上,内存访问必须与操作数的大小对齐,因此大多数(但不是全部)时间,尝试取消引用(uint32_t*)&arr[1]会使程序崩溃SIGBUS ,由内存总线引起的硬件错误。 编译器使您可以像这样用脚射击自己。 像您一样强制转换指针违反了C的严格别名规则,这会导致未定义的行为

您可以通过编写uint32_t x; memcpy( &x, &array[1], sizeof(x) )来解决此问题uint32_t x; memcpy( &x, &array[1], sizeof(x) ) uint32_t x; memcpy( &x, &array[1], sizeof(x) ) ,该标准明确允许。 从这一点开始,我将假设您正在执行与此等效的操作。 如果未在数组中使用偏移量,则还可以在C中使用联合字段键入= pun(尽管C ++中的规则不同)。

按照标准,数组的元素必须连续存储,并且它们之间没有填充。 在某个对象x与一个unsigned char[sizeof(x)]数组之间的memcpy()是合法的,其结果称为其对象表示

使用memcpy()将任意位复制到<stdint.h>的任何精确宽度类型的对象表示形式是未指定的行为 ,而不是未定义的行为 这是一个格式正确的程序,即使语言标准没有说明必须写的内容,您也会从其中得到一些有效的uint32_t 您没有授予编译器执行所需的任何权限的权限,例如Kill All Humans。 这仅是因为该标准不允许精确宽度整数类型具有除值位以外的任何其他位,因此,它们不能具有陷阱表示形式 ,即无效位模式,如果将其复制到该类型的值中会导致未定义的行为。 (标准中的示例是在每个字中存储一个奇偶校验位的实现。)

但是,这种保证的另一面是,不保证uint8_tuint32_t类型不存在,并且在现实世界中有一些体系结构永远不会存在它们的符合版本。 (但是, unsigned char array[sizeof(uint_least32_t) + 1]可以保证正常工作。)

文艺青年最爱的

可以在其上正确运行代码的真实世界小端实现可能会告诉您*u32 0x050403020x05040302 否则,我们将其称为little-endian以外的东西。 但是,某些编译器让程序员有责任严格遵循严格的锯齿规则。 众所周知,它们会产生优化的代码,如果您通过任何一个指针编写代码,它们都不会达到您的期望。

1:8位MCU / MPU /平台-小端

 uint8_t arr[5] = {0x1,0x2,0x3,0x4,0x5};//assume &arr[0] == 0x0 uint32_t *ui32 = (uint32_t*)&arr[1]; 

*ui32的值是*ui32

由于通过不同类型的左值读取对象( arr一部分)的值,因此C明确声明在这种情况下读取*ui32的值的效果是不确定的。

0x2030405

绝对不能保证,但在实践中并不少见,通过读取*ui32所获得的值将是将包含arr元素1-4的位模式解释为uint32_t的位模式的值,但未指定代表什么数字。 由实现方式决定如何将物理字节映射到逻辑字节。

但是,如果使用“ little-endian”,则表示C实现的uint32_t由最低有效位到最高有效位的4-8位字节序列表示,并且如果您认为取消引用指针确实可以成功解释指向uint32_t的指向位模式,则结果值将与整数常量0x05040302u表示的值0x05040302u

是否需要在此平台uint32_t变量放置到4的地址倍数上?

您还没有指定一个平台,甚至也不是一个特别窄的平台。 通常,我希望8位平台不需要为uint32_t类型的对象要求4字节对齐,但是C没有指定,平台和实现可能会有所不同。

1:32位MCU / MPU /平台-小端

几乎相同的示例:

答案完全相同,只是类型uint32_t对象更有可能(但不确定)是4字节对齐。

我知道32位变量应该驻留在4的地址倍数中。

不必要。 确实某些32位平台确实需要它。 有些不需要它,但是可以更快地访问对齐的对象; 有些根本不在乎。

在哪里可以找到规范?

您感兴趣的C实现的此类详细信息可以在该实现的文档中找到。 基础系统的ABI和/或硬件文档可以用作辅助资源。

总体而言,最好的建议通常是完全避免此类问题。 避免未指定的,未定义的,特别是未定义的行为,将使您完全依赖C标准来预测程序的行为。

8位MCU / MPU /平台-小端

答案将假定该平台以某种方式支持更长的整数(即使CPU可能不支持),并且它们是低位优先的。

请注意,如果uC确实是8位的,并且没有更长整数的概念,那么谈论它的(字节)字节顺序就没有多大意义。 例如,我们可以说它既是little-endian,又是big-endian(或者不是全部)。

 //assume &arr[0] == 0x0 

这可能暗示这是来自一些有关未对齐访问的练习。

*ui32的值是*ui32 0x2030405 是否需要在此平台uint32_t变量放置到4的地址倍数上?

它取决于平台和编译器的选项(例如,如果编译器采用严格的别名,则从一开始就是未定义的行为)。

但是,由于这是8位平台(并且假设您告诉编译器执行您想做的事情),因此可以合理地猜测到uint32_t必须在软件中得到支持,并且未对齐的访问不是问题。 假设该软件实现将整数作为低位字节序存储在内存中(如上所述),那么是的,一个很好的猜测将是0x05040302

32位MCU / MPU / Platform-小字节序 *ui32的值是*ui32

同样,在这种情况下,它取决于平台/编译器。 在其中一些中,甚至没有任何值,因为当您尝试读取这样的地址时,CPU会陷阱(因为&arr[0] == 0ui32 == 1 ,它未对齐例如4)。

我知道32位变量应该驻留在4的地址倍数中。

通常,但取决于平台。 另外,即使平台支持不对齐访问,也可能比对齐访问要慢(因此无论如何都希望它们对齐)。

在哪里可以找到规范?

除了C规范之外,您还需要查看编译器的文档和体系结构的手册。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM