sap*_*api 5 c embedded endianness
我有一个16位变量data,即:
volatile uint16_t data;
Run Code Online (Sandbox Code Playgroud)
我需要根据外部传感器上两个8位寄存器的内容填充该值.这些通过I2C/TWI访问.
我的TWI例程是async*,并且有签名:
bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void));
Run Code Online (Sandbox Code Playgroud)
这读取的价值reg就sla成*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);
Run Code Online (Sandbox Code Playgroud)
但是,我不喜欢将endian依赖到我的代码中.有没有办法以与endian无关的方式实现这一目标?
(旁注:我目前的实际解决方法是使用结构,即:
typedef struct {
uint8_t msb;
uint8_t lsb;
} SensorReading;
Run Code Online (Sandbox Code Playgroud)
但我很好奇,如果我能用一个简单的方法做到这一点uint16_t)
编辑
(*async我的意思是分裂阶段,*data即将在未来的某个时间点设置,此时callback如果请求,将通过函数通知被调用者)
下面的方法不行吗?
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;
Run Code Online (Sandbox Code Playgroud)
或者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
Run Code Online (Sandbox Code Playgroud)
最重要的是你可以放一个union
union
{ uint16_as_uint8_t as8;
uint16_t as16;
};
Run Code Online (Sandbox Code Playgroud)
请注意,后者违反了 C89 标准,因为您明确意图写入一个字段union并从另一个字段读取,这会导致未指定的值。从 C99 开始(幸运的是)这是支持的。在 C89 中,可以使用指针转换来(char*)以可移植的方式完成此操作。
请注意,上面的内容似乎以可移植的方式隐藏了字节顺序,结构打包也可能因目标而异,并且在某些目标上仍然可能会中断。对于上面的例子来说,这不太可能,但是周围有一些奇怪的目标。我想说的是,在这个设备级别上进行可移植编程可能是不可能的,最好接受这一点并努力将所有细节隐藏在紧凑的目标接口中,因此更改目标的一个头文件就足以支持它。代码的其余部分看起来可以与目标无关。