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

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

本文关键字:const 工作 不应该 scanf int 带有      更新时间:2023-10-16

我有如下代码:

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

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

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

scanf的原型是:

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

省略号表示它接受变量参数。C(和c++)没有办法检查这些参数的有效性。这就是为什么如果你在这里传递双精度变量的地址,甚至是双精度变量本身,你都不会得到错误。由程序员来验证传递的参数是否正确。

scanf几乎没有类型安全,它很高兴地做你告诉它的事情。这是因为变量参数列表在c中实现的方式,它们期望类型是你告诉它的类型。

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

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

由于scanf是可变的,它在语法上是合法的传入几乎任何东西,因此它也应该编译。

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

最后,fscanf的标准文档说

将转换结果放置在format实参后面的第一个实参所指向的对象中,该对象尚未接收到转换结果。如果该对象没有适当的类型,或者转换的结果不能在该对象中表示,则该行为为未定义。

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

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

好吧,scanf不会区分传递的参数,但如果你编译时启用了警告,编译器会警告你-

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