我的代码相当于以下内容:
const int* const n = new int;
printf("input: ");
scanf("%d", n);
delete n;
现在,因为n是指向CONSTANT整数的指针,所以这不应该工作(我期待编译器错误)。但是,这似乎可以正常工作,甚至可以将输入值存储到* n。
我想知道,为什么这不会给我一个错误;它为什么有效?扫描不应该无法改变* n?
的值答案 0 :(得分:23)
scanf的原型是:
int scanf ( const char * format, ... );
省略号表示它需要变量参数。 C(和C ++)无法检查这些参数的有效性。这就是为什么如果你传递double的地址或者甚至是double变量本身你都不会得到错误的原因。由程序员来验证是否传递了正确的参数。
答案 1 :(得分:5)
scanf
旁边没有任何类型安全,它很乐意按照你的说法去做。这是因为变量参数列表在C中实现的方式。他们希望类型是你告诉它的类型。
因此,如果您为scanf
提供一个不匹配的转换说明符,您将调用在运行时发生的未定义行为。类似地,编译器可能无法判断传递的指针是否为const type* const
类型。一个好的编译器可以提供诊断,如果它发现了一些可疑的东西,但绝不需要这样做。
由于大多数未定义行为的情况都发生在运行时,因此程序员通常有责任了解各种形式的未定义行为并避免它们。
答案 2 :(得分:3)
由于scanf
是可变参数,因此在语法上合法传递任何内容,因此它也应该编译。
虽然n
是指向const int
的指针,但它指向的对象实际上是而不是一个const对象。因此,修改int
对象(例如,使用const_cast
将指针转换为int*
)是明确定义的行为。
最后,fscanf
的标准文档说
转换的结果放在第一个参数指向的对象之后,该参数位于尚未收到转换结果的format参数之后。如果此对象没有适当的类型,或者无法在对象中表示转换结果,则行为未定义。
实际上,指针指向适当类型的对象;总之,我认为这是明确定义(但令人困惑)的行为。
答案 3 :(得分:2)
编译器可以发出警告,但它不会阻止你犯这样的错误,它的未定义行为,const
仅用作指示符,它不会阻止编译。并且它正常工作,因为指针实际上不是const
,虽然它的 UNDEFINED BEHAVIOR 传递const
指针,但这不是真的。
答案 4 :(得分:1)
好吧,scanf
不会区分传递的参数,但如果你在启用警告的情况下编译,编译器会警告你 -
warning: writing into constant object (argument 2) [-Wformat]