如何在C中从给定的字符指针读取4字节的数据

如何在C中从给定的字符指针读取4字节的数据,c,arrays,pointers,byte,cortex-m,C,Arrays,Pointers,Byte,Cortex M,场景是,我想从一个char类型的给定指针读取4个字节的数据。 EG: < /强>考虑以下- int a=0; char* c; // This will have some address 我想做的是从c(即地址)开始读取4个字节,并将它们分配到变量a中,变量a是一个整数 我的解决方案: a = *(int*)c; // Assembly is LDR r1, [r6,#0x00] 我的问题: 上述解决方案在某些体系结构上运行良好,但在某些体系结构上失败。 具体来说,在我的例子中


场景是,我想从一个char类型的给定指针读取4个字节的数据。
<强> EG: < /强>考虑以下-

int a=0;
char* c; // This will have some address 
我想做的是从c(即地址)开始读取4个字节,并将它们分配到
变量a中,变量a是一个整数

我的解决方案:

a = *(int*)c;  // Assembly is LDR    r1, [r6,#0x00]
我的问题:
上述解决方案在某些体系结构上运行良好,但在某些体系结构上失败。 具体来说,在我的例子中,它在Arm CortexM0上失败

如果任何人有任何便携式、高效(装配最少)替换我的解决方案,请与我分享,这将对我有很大帮助,我提前对此表示感谢;)

请询问是否需要更多信息。

问题可能是因为对齐。某些CPU架构无法在未对齐的地址上读取或写入非字节值

解决方案是进行未对齐字节访问,这可以通过以下方式轻松完成:

取决于

#包括
内部主(空)
{
无符号字符字节[]={0xAA,0x55,0xAA,0x55};
无符号整数a=0;
无符号字符*c=字节;

a+=(*c++&0xFFFFFFFFu)如果endianness是您的问题:

而不是:

a = *(int*)c;  // Assembly is LDR    r1, [r6,#0x00]
你需要这个:

关于big-endian系统:

a = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
a = c[3] << 24 | c[2] << 16 | c[1] << 8 | c[0];

// probably faster (only on little endian systems) :
memcpy(&a, c, sizeof a);

a=c[0]这里有许多不同的问题

  • 对齐。如果要在对齐地址读取整数,字符指针必须指向该地址
  • char
    的有符号性。是否将
    char
    视为有符号还是无符号是由实现定义的。因此,任何形式的位/字节操作都不能使用该类型。请改用
    uint8\u t
  • 指针别名。将
    char*
    指向的原始地址强制转换为
    int*
    是未定义的行为,因为它违反了所谓的规则。这可能会导致编译器(特别是gcc)错误地优化代码。相反,从
    int*
    char*
    也可以
如果存储的整数的Endianess格式与当前系统的Endianess格式相同,则Endianess不是问题。如果不是,则必须将其转换,但这与此处的问题无关

便携式安全解决方案示例:

#include <stdint.h>
#include <assert.h>
#include <string.h>

#include <stdio.h>
#include <inttypes.h>


int main (void) {

  int x = 123;
  uint8_t* c = (uint8_t*)&x; // point to something that is an int
  assert((uintptr_t)c % _Alignof(uint32_t) == 0); // ensure no misalignment

  uint32_t i;
  memcpy(&i, c, sizeof(i)); // safely copy data without violating strict aliasing

  printf("%"PRIu32, i); // print 123

  return 0;
}
#包括
#包括
#包括
#包括
#包括
内部主(空){
int x=123;
uint8_t*c=(uint8_t*)&x;//指向一个整数
assert((uintpttr_t)c%\u Alignof(uint32_t)==0);//确保没有未对齐
uint32_t i;
memcpy(&i,c,sizeof(i));//在不违反严格别名的情况下安全地复制数据
printf(“%”PRIu32,i);//print 123
返回0;
}

描述它是如何失败的。
c
是否指向另一个整数?该解决方案可能仍然存在端点问题。@someProgrammerDude:虽然这可以解决问题,但如果你比较效率,我的代码会生成一条加载指令。你的代码会生成大量额外的memcpy调用代码b/c。此外,我不知道ve memcpy可在以下位置获得:(@ MRMJ大多数编译器都有专门处理<代码> MycPy < /代码>的方法,使它们非常高效,甚至可以用少量的指令直接替换它们。你说你只能用一个指令来编码它,但是如果问题是对齐的话,那么实际上你不能只用一个指令来做它。你也应该考虑MeNTAI。代码的可识别性和易读性,特别是在endianness不是问题的情况下。最后,为什么不尝试一下呢?通过优化构建并查看生成的汇编代码?@Mrmj,注意未对齐的访问在Cortex-M0()上无效。@Mrmj最后,Cortex M0默认为小endian(is),这意味着如果您与其他little endian系统(所有x86系统都是这样)通信,则故障的唯一可能原因是对齐。但我们实际上不知道这一点,因为您的问题太模糊了。这会产生很多问题(至少从我的观点来看)与我的指令相比,我的指令只生成一条汇编指令。正如我所写的:如果你知道endianness问题,你可以自由使用你的方法。否则你必须处理它。为什么他会在内存中有一个指向整数的指针,而整数的endianness与CPU的endianness不同?这似乎与问题无关。@Lundin我见过太多次这样的代码访问字节数据包的有效负载以提取数据(例如modbus)。所以我可能有偏见;)为什么他会在内存中有一个指向整数的指针,而这个整数与CPU的endianess不同?这似乎与问题无关。
a = c[3] << 24 | c[2] << 16 | c[1] << 8 | c[0];

// probably faster (only on little endian systems) :
memcpy(&a, c, sizeof a);
#include <stdint.h>
#include <assert.h>
#include <string.h>

#include <stdio.h>
#include <inttypes.h>


int main (void) {

  int x = 123;
  uint8_t* c = (uint8_t*)&x; // point to something that is an int
  assert((uintptr_t)c % _Alignof(uint32_t) == 0); // ensure no misalignment

  uint32_t i;
  memcpy(&i, c, sizeof(i)); // safely copy data without violating strict aliasing

  printf("%"PRIu32, i); // print 123

  return 0;
}