带有 const int* const 的 scanf 可以工作,但不应该

scanf with const int* const works, but shouldn't

我有等同于以下的代码:

const int* const n = new int;
printf("input: ");
scanf("%d", n);
delete n;

现在,因为 n 是一个指向 CONSTANT 整数的指针,所以这应该不起作用(我预计会出现编译器错误)。但是,这似乎可以正常工作,甚至可以将输入值存储到 *n.

我想知道,为什么这不给我一个错误;为什么它有效? scanf 不应该不能改变 *n 的值吗?

编译器可能会发出警告,但它不会阻止您犯这样的错误,这是未定义的行为,const 仅用作指示器,它不会阻止编译。它可以正常工作,因为指针不是真正的 const,虽然它是 未定义的行为 来传递 const 指针,但这不是真正的

]

scanf 的原型是:

int scanf ( const char * format, ... );

省略号表示它采用可变参数。 C(和 C++)无法检查这些参数的有效性。这就是为什么在此处传递双精度变量的地址甚至双精度变量本身都不会出错的原因。由程序员来验证是否传递了正确的参数。

好吧,scanf 不会区分传递的参数,但是如果您在启用警告的情况下进行编译,编译器会警告您 -

 warning: writing into constant object (argument 2) [-Wformat]

scanf 几乎没有类型安全性,它会按照您的要求去做。这是因为可变参数列表在 C 中的实现方式。他们希望类型是您告诉它的类型。

因此,如果您给 scanf 一个不匹配的转换说明符,您将调用未定义的行为,这发生在 运行 时间。同样,编译器可能无法判断传递的指针是 const type* const 类型。一个好的编译器可能会在发现可疑之处时给出诊断,但这绝不是必须的。

由于大多数未定义行为的情况发生在 运行 时间内,程序员通常有责任了解各种形式的未定义行为并避免它们。

因为 scanf 是可变的,所以在语法上传递几乎任何东西都是合法的,因此它也应该编译。

虽然 n 是指向 const int 的指针,但它指向的对象实际上 不是 const 对象。因此,修改 int 对象(例如,通过使用 const_cast 将指针转换为 int* 明确定义的行为。

最后,fscanf 的标准文档说

the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.

指针实际上是指向适当类型的对象;总之,我认为这是定义明确(但令人困惑)的行为。