C 你能以一种与endian无关的方式得到一个指向低位字节的指针吗?

C 你能以一种与endian无关的方式得到一个指向低位字节的指针吗?,c,embedded,endianness,C,Embedded,Endianness,我有一个16位变量数据,即: volatile uint16_t data; 我需要根据外部传感器上两个8位寄存器的内容填充此值。这些都是通过I2C/TWI访问的 我的TWI例程是async*,具有以下签名: bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void)); 这会将sla上的reg的值读取到*数据中,然后调用callback() 如果我知道uint16\t在内存中被

我有一个16位变量
数据
,即:

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

我的TWI例程是async*,具有以下签名:

bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void));
这会将
sla
上的
reg
的值读取到
*数据中,然后调用
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依赖。有没有一种方法可以独立于endian实现这一点

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

typedef struct {
    uint8_t msb;
    uint8_t lsb;
} SensorReading;
但我很好奇我是否能用一个简单的
uint16\u t

编辑


(*所谓异步,我指的是分相,即
*数据
将在将来的某个时间点设置,在该时间点,如果被请求,将通过
回调
函数通知被调用方)

以下操作是否无效

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;
除此之外,您还可以放置一个
联合体

union
{       uint16_as_uint8_t  as8;
        uint16_t           as16;
};
请注意,后者违反了C89标准,因为您显然打算写入
联合
的一个字段并从另一个字段读取,这会导致未指定的值。从off C99开始(幸运的是)支持此功能。在C89中,可以使用通过
(char*)
的指针转换以可移植的方式进行转换


请注意,上述内容似乎以便携方式隐藏了端部性,结构包装也可能因目标不同而有所不同,并且在某些目标上仍可能断裂。对于上面的例子来说,这是不可能的,但是周围有一些奇怪的目标。我想说的是,在这个设备级别上编程portable可能是不可能的,最好接受这一点,并努力在紧凑的目标接口中隐藏所有细节,因此为目标更改一个头文件就足以支持它。代码的其余部分可以看起来与目标无关。

类似的东西怎么样

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

但是,不确定您为什么要提到
volatile
twi\u read\u register
是异步/分相的,因此您的示例中的
v1
v2
直到将来的不确定时间才会设置<代码>数据
将有一个未定义的值。我明白了。如果
数据
确实由其他设备拥有,并且在读取
数据
时应用程序无法控制,则在知道值已准备好后,您可以将其合并到
uint16\t
。@AlexeyFrunze,然后我们真的需要将它的地址传递给twi设备,我们只能使用依赖于endian的代码。是的,它不受应用程序的控制。我想知道是否有一些方法可以独立于endianness(我实际上知道目标系统的endianness,它不会改变,但我不喜欢编写依赖于它的代码,因此采用了struct workaround atm)。为什么要限制自己对16位值的指针访问?大多数人会使用shift和add或运算符来执行此操作。然而,如果你真的想用指针来做这件事,你可以使用宏来检测和补偿端点。不,你不能…可靠地。如果你想要可靠和可移植的代码,就使用掩码和移位。实际上掩码和移位也不起作用,是吗?@ChrisStratton-掩码和移位根本不适用于分相调用,因此问题就来了。在调用read之后,当read函数还没有实际设置值时,屏蔽和移位是不好的。读入临时值,然后在收到读取完成的通知时通过屏蔽和移位组合。即使使用指针,您也不能使用请求读取的时间和通知读取完成的时间之间的值,因为如果中途捕获,则可能会有不一致的高字节和低字节。这是一种常见的方法,尽管我对这个问题的理解是,它会在另一个方向提出问题,从两个8位值填充一个16位值。“myValue=MSB*256+LSB;”
uint16_t myValue = ...;
uint8_t LSB = (uint8_t)(myValue % 256);
uint8_t MSB = (uint8_t)(myValue / 256);
  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);