val*_*tin 2 c c++ arrays pointers strict-aliasing
为什么这样做呢?
uint8_t array[4] = {1,2,3,4};
uint8_t* parray = array;
uint8_t (*p1)[4] = (uint8_t (*)[4])&array;
uint8_t (*p2)[4] = (uint8_t (*)[4])&parray;
uint8_t (*p3)[4] = (uint8_t (*)[4])parray;
uint8_t test1 = **p1; // test1 = 1
uint8_t test2 = **p2; // test2 = something random
uint8_t test3 = **p3; // test3 = 1
Run Code Online (Sandbox Code Playgroud)
parray显然与数组几乎相同.例如,array [0] == parray [0].但是当我想将指向数组的指针作为指向固定大小数组的指针时,我必须使用&符号.当我想要得到的指针粒子阵列,我不得.
实际的例子.
有一个函数接受指向固定大小数组的指针
void foo(uint8_t (*param)[4])
{
...
}
Run Code Online (Sandbox Code Playgroud)
当我将另一个函数中的param作为指针时,我可以通过这种方式传递给foo吗?
void bar(uint8_t param*)
{
uint8_t (*p)[4] = (uint8_t (*)[4])param;
foo(p);
}
Run Code Online (Sandbox Code Playgroud)
有没有更好的办法?
这是一种称为阵列衰减的功能.当在值上下文中使用变量名时,数组变量被称为衰变为指向第一个元素的指针.
这里的数组用于值上下文:parray = array,因此它会衰减.你可以明确地写出衰变:parray = &(array[0]).前(隐式衰变)只是后者的语法糖.
addressof运算符的操作数不是值上下文.因此,阵列名称不会衰减.&array不同于&(array[0]).首先获取数组类型的地址,后者获取元素类型的地址.parray另一方面,它是一个完全不同的变量,并&parray返回存储指针的地址,这不是存储数组的地址.
Run Code Online (Sandbox Code Playgroud)uint8_t (*p1)[4] = (uint8_t (*)[4])&array;
这是正确的,虽然转换是多余的,因为&array已经是类型uint8_t (*)[4].
Run Code Online (Sandbox Code Playgroud)uint8_t (*p2)[4] = (uint8_t (*)[4])&parray;
这是错的.parray是类型uint8_t*,它存储的地址不包含类型的对象uint8_t[4].相反,它包含指针.
Run Code Online (Sandbox Code Playgroud)uint8_t (*p3)[4] = (uint8_t (*)[4])parray;
这有点可疑.parray是指针uint8_t,而不是指针uint8_t[4].但是,它碰巧指向一个也包含uint8_t[4]对象的地址,因此这很有效.
parray显然与数组几乎相同
但显然不完全相同,正如您的程序行为所证明的那样.
array是一个包含四个uint8_t元素的数组,并且parray是指向uint8_t第一个元素的指针array.这种区别对于理解很重要.
结论:了解数组衰减是什么,以及数组和指针之间的区别是很重要的,最重要的是:显式转换可以隐藏编译器的错误 - 尽可能避免它们.
对于编辑:
当我将另一个函数中的param作为指针时,我可以通过这种方式传递给foo吗?
只有你能证明param指向一个元素的第一个元素
uint8_t[4].这基本上是一个先决条件bar.
但是,当您可以使用类型系统来传达要求时,最好不要依赖语言前置条件:
有没有更好的办法?
更改参数类型bar,以便用户知道传递正确类型的指针:
void bar(uint8_t (*param)[4]) {
foo(param);
}
Run Code Online (Sandbox Code Playgroud)
当然,这bar在这个简单的例子中是多余的.
| 归档时间: |
|
| 查看次数: |
1026 次 |
| 最近记录: |