我在我正在做的项目中偶然发现了一些代码,我想确保正确理解它。这里是:
uint16_t* tmp;
tmp = (uint16_t*) ((uint8_t*)getVariableAddress(variable) + offset);
tmp = (uint16_t*)((uint8_t*)tmp + otherOffset);
Set_Register((unsigned long) tmp[0]);
Set_OtherRegister((unsigned long) tmp[2]);
起初我在所有类型转换之间有点迷路,但我看到uint8_t*被用来每字节移动一个字节,并将偏移值添加到我们在tmp中放置的基址,这是让我感到困扰的第一部分。第二部分是在uint16_t*上使用[],对于这个,我完全不确定结果,有人愿意详细解释这一点吗?
感谢我想如果我们重写一下代码会更容易看到发生了什么:
// We keep this as a `uint8_t *` so we can add offsets correctly.
uint8_t *base_address = (uint8_t *)getVariableAddress(variable);
// Add the offsets to the base address.
uint8_t *offsetted_address = base_address + offset + otherOffset;
// We want it as a uint16_t.
uint16_t *as_u16 = (uint16_t *)offsetted_address;
// We want to write the first register with the first `uint16_t` at `offsetted_address`, but `Set_Register` takes the value as `unsigned long`.
unsigned long first_u16 = as_u16[0];
Set_Register(first_u16);
// We want to write the other register with the third `uint16_t` at `offsetted_address`, but `Set_OtherRegister` takes the value as `unsigned long`.
unsigned long third_u16 = as_u16[2];
Set_OtherRegister(third_u16 );
我们知道我们感兴趣的值相对于getVariableAddress
返回的地址有一个偏移。为了正确地计算该地址,我们将地址强制转换为uint8_t
。如果我们保持uint16_t
不变,我们的计算就会出错。想想看:
uint8_t *p = (uint8_t *)0x100;
printf("%pn", p + 1); // prints 0x101
uint16_t *q = (uint16_t *)0x200;
printf("%pn", q + 1); // prints 0x202
然后我们想要从我们刚刚计算的地址中读取第一个和第三个16位无符号整数,所以我们将其转换为uint16_t *
并获得第一个([0]
)和第三个([2]
)整数。
当你使用诸如:
int var[5];
var[3] = 1;
当声明var
时,它在内存中连续分配5个整数,var
只获得指向这5个内存槽中的第一个的指针,本质上是一个int*
。
然后当你用var[3]
访问它时,你告诉它访问第一个内存地址,偏移量是sizeof(int)的3倍。
在您的示例中,它正在做同样的事情,您正在获得指向tmp
指向的第一个内存位置的指针,然后为其添加值的偏移
otherOffset
以字节为单位,但tmp
是uint16_t *
。如果地址计算为tmp + otherOffset
,则将otherOffset
视为uint16_t
对象的数量而不是字节数来计算总和。因此,为了进行所需的计算,将tmp
转换为uint8_t *
。然后(uint8_t *) tmp + otherOffset
以字节为单位进行计算。
同样,offset
以字节为单位,getVariableAddress(variable)
的类型可能不是指向字节/字符类型的指针(因为您没有向我们展示它的声明,我们不知道),因此强制转换确保以所需的单位(字节)进行算术运算。
对uint16_t *
的强制转换只是将算术运算的结果转换为所需的指针类型,以供以后使用。
tmp[0]
和tmp[2]
是下标的普通用法。实际上,它们说,"有一个uint16_t
数组,从tmp
指向的位置开始。给我数组中索引为0或2的元素"形式上,tmp[i]
被定义为*(tmp + i)
,表示将偏移量i
添加到tmp
上,然后对结果地址解引用。