如何在C语言中将一个32位的长整型数值分割成四个8位的字符变量?

11

我有一个32位长整型变量,CurrentPosition,我想把它分成4个8位字符。在C语言中,最有效的方法是什么?我正在使用一个8位MCU,8051架构。

unsigned long CurrentPosition = 7654321;
unsigned char CP1 = 0;
unsigned char CP2 = 0;
unsigned char CP3 = 0;
unsigned char CP4 = 0;
// What do I do next? 

我应该使用指针引用CurrentPosition的起始地址,然后将该地址加8两次,共执行四次吗?

这是小端字节序。

同时,我希望CurrentPosition保持不变。


我正在使用SDCC,它使用小端格式。 - PICyourBrain
6个回答

24
    CP1 = (CurrentPosition & 0xff000000UL) >> 24;
    CP2 = (CurrentPosition & 0x00ff0000UL) >> 16;
    CP3 = (CurrentPosition & 0x0000ff00UL) >>  8;
    CP4 = (CurrentPosition & 0x000000ffUL)      ;

你也可以通过指针来访问这些字节,

unsigned char *p = (unsigned char*)&CurrentPosition;
//use p[0],p[1],p[2],p[3] to access the bytes.

  1. 我需要用 (unsigned char) 进行转换吗?
  2. 这会不会影响 CurrentPosition?
- PICyourBrain
1
  1. 前者需要强制转换
  2. 两种方法都不会影响CurrentPosition
- Saul
前者不需要强制转换,但如果您不这样做,一些编译器会发出虚假警告,提示可能会丢失精度。 - caf
1
请注意,位移版本是端中立的,使其更具可移植性。 - user694733

7

我认为你应该考虑使用union:

union {
   unsigned long position;
   unsigned char bytes[4];
} CurrentPosition;

CurrentPosition.position = 7654321;

现在可以通过以下方式访问这些字节:CurrentPosition.bytes[0],...,CurrentPosition.bytes[3]。

在实践中是一个好主意,因为编译器可以将int分解为字节。但从理论上讲,这是一个坏主意,因为这种使用联合体在C标准中是未定义的。(尽管大多数实现都可以正常工作) - Nils Pipenbrinck
1
@Nils 自 C99 以来,使用联合体进行类型转换已经得到了很好的定义。但代码仍然依赖于大小端。 - user694733

2

如果您正在使用8位MCU,那么移动整个32位变量是一项繁重的工作。在这种情况下,最好使用指针算术读取CurrentPosition的4个字节。强制转换:

unsigned char *p = (unsigned char*)&CurrentPosition;

这不会改变CurrentPosition,但如果您尝试写入p [0],则会更改CurrentPosition的最低有效字节。如果您想要一个副本,请执行以下操作:

unsigned char *p = (unsigned char*)&CurrentPosition;
unsigned char arr[4];
arr[0] = p[0];
arr[1] = p[1];
arr[2] = p[2];
arr[3] = p[3];

并且与arr一起工作。(如果您想要最高位字节在前,请更改这些赋值的顺序)。

如果您更喜欢4个变量,那么您可以显然地执行以下操作:

unsigned char CP1 = p[0];
unsigned char CP2 = p[1];
unsigned char CP3 = p[2];
unsigned char CP4 = p[3];

如果您无法直接转换32位整数,则此解决方案更好。 - Paul Nathan

0
unsigned char *CP = &CurrentPosition;

现在,根据您的原始代码,CPn 可以通过 CP[n] 访问。


0
CP1 = (unsigned char)(CurrentPosition & 0xFF);
CurrentPosition >>= 8;
CP2 = (unsigned char)(CurrentPosition & 0xFF);
...

这会改变CurrentPosition的值,对吧?我想保持CurrentPosition不变。 - PICyourBrain
是的,这样做是可行的。其中一种方法是复制CurrentPosition并对其进行修改。或者nos的答案也是另一种选择。您使用指针的想法也是可行的。有很多方法可以实现这个功能。 - Matt Greer

0

我知道这个帖子是一段时间之前发布的。但是对于任何仍在阅读该线程的人: 许多人采用逐步移动原始值的方法。为什么不让编译器为您完成工作呢? 使用共同体(union)&,使您能够在同一位置存储值。定义一个包含32位长变量(这将是您保存当前位置的位置)和由4个字符变量组成的结构的联合体。或者只是一个简单的8位整数数组。当您将CurrentPosition写入长变量时,它将存储在读取4个字符变量时访问的相同位置。此方法工作量小,不浪费时间和资源,而且可以让编译器执行工作。


1
这正是第二个最受赞同的答案所建议的。 - Jongware

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接