6.5(p7)
说明:
一个对象的存储值只能由左值访问 表达式具有以下类型之一:88)
-与对象的有效类型兼容的类型,
-与对象的有效类型兼容的类型的限定版本,
-是 对应于有效类型的有符号或无符号类型 对象
-一种类型,它是与以下类型对应的有符号或无符号类型 对象的有效类型的限定版本,
看看6.7.3(p10)
:
要使两个合格的类型兼容,两个都应具有 兼容类型的完全相同的版本;
因此double
和const double
不兼容,因为它们的类型限定符不同。
现在,我假设带符号或无符号类型是指{strong>带符号或无符号整数类型,定义为6.2.5(p4)
和6.2.5(p6)
自{{1 }}本身未定义签名类型。
现在考虑以下代码:
6.2.5
现在,我尝试申请void print_double(const double d){
printf("d = %lf\n", d);
}
int main(int args, const char *argv[]){
double d = 10.2;
print_double(d);
}
:
I。 6.5 (p7)
否,a type compatible the effective type of the object
和const double
不兼容。
II。 double
否,a qualified version of a type compatible with the effective type of the object
的合格版本将使其比const double
更加合格
III / IV。
否,const double
不是有符号或无符号整数类型。
此判断似乎是错误的,因为可以通过const限定的左值访问非const对象。但是我不能从double
中得出结论。
答案 0 :(得分:7)
现在考虑以下代码:
void print_double(const double d){ printf("d = %lf\n", d); } int main(int args, const char *argv[]){ double d = 10.2; print_double(d); }
您的代码没有任何别名。 main中的d
和d
中的print_double
是 distinct 对象,因为参数总是按值传递。但是,如果我们要“修复”示例:
void print_double(const double *pd){
printf("d = %lf\n", *pd);
}
int main(int args, const char *argv[]){
double d = 10.2;
print_double(&d);
}
它仍然是定义明确的。 *pd
是类型const double
的左值。 const double
是double
的合格版本。所有类型都与它们自己兼容(平凡)。因此第二个项目符号成立,并且该别名有效。
答案 1 :(得分:2)
如果两个指针(左值访问)可能别名与指向兼容类型的指针不同。您引用的部分是关于指针别名(又名“严格别名规则”)的,其原因如下:
- 与对象的有效类型兼容的类型
- 与对象的有效类型兼容的类型的合格版本
这恰好意味着一个const限定对象可能别名一个非限定对象,即使它们不是兼容类型。示例:
void f (const int* a, int* b);
a
可能指向与b
相同的数据。编译器不能随意假设它们指向单独的对象。
但这不适用于您的情况,因为您通过值传递参数并创建本地副本。如果您的示例是这样,则将使用别名:
double a = 10.2;
int main(int args, const char *argv[]){
print_double(&a);
}
void print_double(const double* b){
printf("d = %lf\n", b);
}
其中参数b
是与对象的有效类型(double
)兼容的类型的合格版本。因此,编译器可能不会假设b
没有指向全局变量a
。
关于兼容性:
每当通过赋值=
或通过将其作为参数传递给函数来复制对象时,都会引入简单赋值规则。6.5.16.1允许这样做:
- 左操作数具有原子,合格或不合格的指针类型,并且(考虑到 左值转换后左操作数将具有的类型)两个操作数均为 指向兼容类型的合格或不合格版本的指针,以及指向的类型 到左边的所有限定词都指向右边;
表示int* a; const int* b = a;
很好,但是const int* a; int* b = a;
违反了约束。在参数传递过程中适用同样的规则,请参见6.9.1 / 10:
在进入函数时,每个可变修改参数的大小表达式为 评估,并且每个参数表达式的值都将转换为 相应的参数,就像通过赋值一样。
在您的情况下,将调用者中d
的值复制到类型为const double
的新变量中。根据简单分配的规则,这是允许的,然后您创建一个新变量-一切都很好。