你能以与字节无关的方式获得指向低位字节的指针吗?

时间:2013-04-15 00:44:30

标签: c embedded endianness

我有一个16位变量data,即:

volatile uint16_t data;

我需要根据外部传感器上两个8位寄存器的内容填充此值。这些通过I2C / TWI访问。

我的TWI例程是异步*,并且具有签名:

bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void));

这会将regsla的值读入*data,然后调用callback()

如果我知道uint16_t被安排在内存中,比如MSB LSB,那么我可以这样做:

twi_read_register(SLA, REG_MSB, (uint8_t *)&data, NULL);
twi_read_register(SLA, REG_LSB, (uint8_t *)&data + 1, NULL);

但是,我不喜欢将endian依赖到我的代码中。有没有办法以与端元无关的方式实现这一目标?

(旁注:我目前的实际解决方法是使用结构,即:

typedef struct {
    uint8_t msb;
    uint8_t lsb;
} SensorReading;

但我很好奇我是否可以用简单的uint16_t

来做到这一点

修改

(* by async我的意思是分裂阶段,即*data将在未来的某个时间点设置,此时如果请求,将通过callback函数通知被调用者。

3 个答案:

答案 0 :(得分:4)

以下不起作用吗?

uint8_t v1, v2;
twi_read_register(SLA, REG_MSB, &v1, NULL);
twi_read_register(SLA, REG_LSB, &v2, NULL);
data = ((uint16_t)v1<<8)|v2;

或者data如此易变,twi_read_register需要写它。在这种情况下,我认为你坚持使用依赖于字节序的代码。

正如您在下面指出的那样,data确实是易变的,因为另一个设备正在阅读它。因此,在两个可能在字节序上不同的设备之间建立存储器映射连接。这意味着你会遇到依赖于字节序的代码。

您提到结构作为一种解决方法,但这是处理此问题的标准方法。

#ifdef BIGENDIAN
typedef struct
{       uint8_t  msb, lsb;
} uint16_as_uint8_t;
#else
typedef struct
{       uint8_t  lsb, msb;
} uint16_as_uint8_t;
#endif

最重要的是你可以放union

union
{       uint16_as_uint8_t  as8;
        uint16_t           as16;
};

请注意,后者违反了C89标准,因为您明确打算编写union的一个字段并从另一个字段读取,这会导致未指定的值。从C99开始,这是(幸运的是)支持。在C89中,可以通过(char*)使用指针转换以便携方式执行此操作。

请注意,上面的内容可能会以可移植的方式隐藏字节序,结构打包也可能因目标而异,并且可能仍会在某个目标上中断。对于上面的例子,这是不太可能的,但是有一些奇怪的目标。我想说的是,在这个设备级别上编程可能是不可能的,并且最好接受它并努力隐藏紧凑目标接口中的所有细节,因此更改目标的一个头文件足以支持它。然后,代码的其余部分可以看起来与目标无关。

答案 1 :(得分:0)

这样的事情怎么样?

uint16_t myValue = ...;
uint8_t LSB = (uint8_t)(myValue % 256);
uint8_t MSB = (uint8_t)(myValue / 256);

答案 2 :(得分:0)

  volatile uint16_t data;  
  uint16_t v = 1;
  twi_read_register(SLA, REG_MSB, (uint8_t *)&data + *((uint8_t *)&v), NULL);
  twi_read_register(SLA, REG_LSB, (uint8_t *)&data + *((uint8_t *)&v + 1), NULL);