某些源代码使用符号&(*var)
,其中var
已经是指针,如int *var = ...
。
这两个符号之间有区别吗?
var != &(*var)
?
示例:https://github.com/FreeFem/FreeFem-sources/blob/develop/src/medit/inout_popenbinaire.c#L40
答案 0 :(得分:10)
&(*var)
在编译时评估与var
相同,但请注意一些警告:
var
应该是一个有效的指针,尽管编译器没有理由生成代码来取消引用它。实际上,C11指定&*var
没有未定义的行为,即使var
是空指针。var
不应该是指向void
的指针,但C标准明确允许它适用于这种情况......确实令人震惊。 / LI>
var
是一个包含多个元素的数组,则var
和&*var
具有不同的类型,而sizeof(var)
和sizeof(&(*var))
具有不同的值:第一个是数组的大小,第二个是指向第一个元素的指针的大小。var
是未初始化的指针,则评估var == &(*var)
会给出未定义的行为(因为评估==
的任一侧会给出undefined行为 - 访问未初始化变量的值是给出未定义行为的原因。)您在问题中链接的示例使用此结构无论如何:
#define WrdSiz 4
void getline_bin_float_vertex(int ddim, double *c, int *ref) {
int i;
float ff;
for (i = 0; i < ddim; i++) {
fread((unsigned char *)&(ff), WrdSiz, 1, stdin);
c[i] = ff;
}
fread((unsigned char *)&(*ref), WrdSiz, 1, stdin);
}
程序员正在读取一些浮点值和一个重定向到标准输入的文件中的整数。代码很笨拙且不可移植:
float
的大小默认为4 int
的大小默默地认为是相同的4个字节c
必须是有效指针,除非ddim
为0 ref
必须是有效指针,因为fread
将尝试在其指向的地址存储4个字节,除非流位于文件末尾可以通过这种方式简化和保护代码:
#define WrdSiz 4
/* read values from stdin, return non-zero in case of failure */
int getline_bin_float_vertex(int ddim, double *c, int *ref) {
int i;
float ff;
assert(sizeof float == WrdSiz);
assert(sizeof int == WrdSiz);
assert(dim == 0 || c != NULL);
assert(ref != NULL);
for (i = 0; i < ddim; i++) {
if (fread(&ff, sizeof ff, 1, stdin) != 1)
return -1;
c[i] = ff;
}
if (fread(ref, sizeof(*ref), 1, stdin) != 1)
return -1;
return 0;
}
此源代码的其他部分显示了较差甚至无效的结构,您应该只研究此包以获取不应执行的操作。
答案 1 :(得分:5)
&(*var)
(指针变量)不包含旧版本C的有效地址时, var
可能有undefined behavior。在这种情况下,scared。§6.5.3.2。但是C11标准segmentation fault表明编译器必须在所有情况下都将其处理为等效(包括var
为NULL
时)
当var == &(*var)
包含有效地址时,var
为真。当它包含其他内容(例如NULL
)时,如果您使用非C11符合的非优化编译器,它可能会崩溃(as-if rule)(但是大多数编译器,即使是旧编译器,也不会生成某些编译器)在那种情况下崩溃代码)
但编译器(即使是旧的C99)也允许(在optimize下)到https://play.golang.org/p/d_fQWzXnlAm &(*var)
进入var
答案 2 :(得分:0)
可能是在括号内有一个更长的表达式,但在调试过程中已经减少到这个并留在源代码中。它没有任何意义
编辑 - github示例看起来与我预期的完全一样。