取消引用数组名称
Dereference array name
根据我的理解,数组名不是变量,
那么我们怎么可能像这样取消引用它:
int a[] = {1,2,3,4,5};
void *p = &a;
这是什么意思?
以及为什么我们所有的 MPI 函数都需要这种取消引用?
int buff[2];
...
MPI_Bcast(&buff, 2, MPI_INT, PROC, MPI_COMM_WORLD);
来自 Kernighan & Ritchie:
There is one difference between an array name and a pointer that must
be kept in mind. A pointer is a variable, so pa=a and pa++ are legal.
But an array name is not a variable; constructions like a=pa and a++
are illegal.
"array name" 不存在。可以有一个指向数组第一个元素的指针类型的命名变量。
int a[] = {1,2,3,4,5};
void *p = &a;
a
是一个int类型的指针,指向第一个元素“1”。
p
是一个void指针,赋值后实际指向的是数组第一个元素所在的地址。
我不知道你们的图书馆是怎么运作的。通常,如果您调用的函数应该能够修改指针,则使用此模式。例如,当库分配一个新数组并更新指针引用时,这就是 "useful"。我在引号中写的很有用,因为我认为这不是很好的做法。
数组是一个变量,但它不能赋值给(你不能"move the array")。
在许多上下文中,名称的计算结果为数组第一个元素的地址,但它不等同第一个元素的地址。
您可以在数组名称上使用 sizeof
并获取数组的实际大小(以字节为单位),如果名称等同于指针,则这是不可能的。像这样:
int a[4];
printf("the array a has size %zu\n", sizeof a);
在 8 位 char
和 32 位 int
的机器上,以上将打印 16
。这证明名称 a
指的是 而不是 只是一个指针。
所有 MPI 函数都采用作为 void *
提供的消息缓冲区的开头地址。它们不需要类型化指针,因为有关缓冲区内存布局的所有信息均由 MPI 数据类型提供,在这种情况下 MPI_INT
.
int buff[2];
...
MPI_Bcast(&buff, 2, MPI_INT, PROC, MPI_COMM_WORLD);
这段代码在技术上是错误的。 &buff
是类型 int (*)[2]
的表达式,即指向两个整数元素的数组的指针。尽管它计算出与 buff
相同的地址,但它在指针运算方面具有不同的语义。
正确的表达方式应该是:
MPI_Bcast(buff, 2, MPI_INT, PROC, MPI_COMM_WORLD);
或
MPI_Bcast(&buff[0], 2, MPI_INT, PROC, MPI_COMM_WORLD);
传递 &buff
也是危险的,因为稍后可能决定动态分配 buff
而不是静态分配,例如int *buff = malloc(2 * sizeof(int));
现在&buff
不会指向分配内存的开始,而是指向指针所在的地址,这是完全错误的,MPI不执行指针追逐。如果使用 buff
或 &buff[0]
,则不会发生这种情况。
此外,请注意 &
是 address-of 运算符,即它 returns 是一个引用。要取消引用,请使用 *
运算符。
根据我的理解,数组名不是变量, 那么我们怎么可能像这样取消引用它:
int a[] = {1,2,3,4,5};
void *p = &a;
这是什么意思? 以及为什么我们所有的 MPI 函数都需要这种取消引用?
int buff[2];
...
MPI_Bcast(&buff, 2, MPI_INT, PROC, MPI_COMM_WORLD);
来自 Kernighan & Ritchie:
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a variable; constructions like a=pa and a++ are illegal.
"array name" 不存在。可以有一个指向数组第一个元素的指针类型的命名变量。
int a[] = {1,2,3,4,5};
void *p = &a;
a
是一个int类型的指针,指向第一个元素“1”。
p
是一个void指针,赋值后实际指向的是数组第一个元素所在的地址。
我不知道你们的图书馆是怎么运作的。通常,如果您调用的函数应该能够修改指针,则使用此模式。例如,当库分配一个新数组并更新指针引用时,这就是 "useful"。我在引号中写的很有用,因为我认为这不是很好的做法。
数组是一个变量,但它不能赋值给(你不能"move the array")。
在许多上下文中,名称的计算结果为数组第一个元素的地址,但它不等同第一个元素的地址。
您可以在数组名称上使用 sizeof
并获取数组的实际大小(以字节为单位),如果名称等同于指针,则这是不可能的。像这样:
int a[4];
printf("the array a has size %zu\n", sizeof a);
在 8 位 char
和 32 位 int
的机器上,以上将打印 16
。这证明名称 a
指的是 而不是 只是一个指针。
所有 MPI 函数都采用作为 void *
提供的消息缓冲区的开头地址。它们不需要类型化指针,因为有关缓冲区内存布局的所有信息均由 MPI 数据类型提供,在这种情况下 MPI_INT
.
int buff[2];
...
MPI_Bcast(&buff, 2, MPI_INT, PROC, MPI_COMM_WORLD);
这段代码在技术上是错误的。 &buff
是类型 int (*)[2]
的表达式,即指向两个整数元素的数组的指针。尽管它计算出与 buff
相同的地址,但它在指针运算方面具有不同的语义。
正确的表达方式应该是:
MPI_Bcast(buff, 2, MPI_INT, PROC, MPI_COMM_WORLD);
或
MPI_Bcast(&buff[0], 2, MPI_INT, PROC, MPI_COMM_WORLD);
传递 &buff
也是危险的,因为稍后可能决定动态分配 buff
而不是静态分配,例如int *buff = malloc(2 * sizeof(int));
现在&buff
不会指向分配内存的开始,而是指向指针所在的地址,这是完全错误的,MPI不执行指针追逐。如果使用 buff
或 &buff[0]
,则不会发生这种情况。
此外,请注意 &
是 address-of 运算符,即它 returns 是一个引用。要取消引用,请使用 *
运算符。