微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

scanf() 是否更新常量变量?

如何解决scanf() 是否更新常量变量?

似乎 scanf() 更新了常量变量。

据我所知,常量变量应该有固定值。

在下面的代码中...

#include <stdio.h>

int main () {
    const int testInteger = 0;

    printf("Before 'scanf',the value of the variable 'testInteger' is %d.\n",testInteger);

    // Does 'scanf' update constant variables?
    printf("Enter an integer: ");
    scanf("%d",&testInteger);

    printf("After 'scanf',testInteger);

    return 0;
}

...通过输入“50”的值,它给出以下输出

Before 'scanf',the value of the variable 'testInteger' is 0.
Enter an integer: 50
After 'scanf',the value of the variable 'testInteger' is 50.

我想知道为什么 scanf() 会更新 'testInteger' 常量变量的值。

解决方法

是的,它应该具有恒定值,但它并不能神奇地保证它。

您获取了这个变量的地址(const int * 类型),它只不过是一个指向某个内存的数字。然后,通过将它传递给 scanf,你违反了 const-ness 的契约(你没有收到任何警告吗?你用 -Wall 编译吗?):它被用作常规 {{1 }} 指针。

,

C 依赖硬件来强制 const 变量的只读性。大多数计算机硬件只能强制读取大内存块(称为“页面”),而不是单个 int 大小的变量。

您将 testInteger 声明为 const int,但是因为它是一个普通的局部变量——它具有“自动存储持续时间”,在 C 标准的语言中——它的存储是分配在一个位置(称为“堆栈”)中,该位置的大块必须保持可写才能正常运行程序,因此硬件无法强制执行其const性。

如果将 testInteger 的声明更改为 static const int testInteger,或者将其声明为全局,那么它将被分配在为 const 变量保留的特殊内存区域中( “只读数据段”),其内存块不可写的,当您的程序尝试写入 scanf 时,它会在 testInteger 的内部崩溃。

const 数据对象声明为全局对象/具有静态存储持续时间无论如何几乎总是正确的,因此这种硬件限制在实践中并不是什么大问题。 (嗯,实际上,这很重要,但原因完全不相关。)

,

这里有几个问题。

首先,const only 的意思是“这个东西可能不是赋值运算符的目标”,不是“这个东西必须存储在 read-只有记忆。”如果 const 限定的变量是赋值运算符的目标,编译器只需要求发出诊断信息。

其次,%dscanf 转换说明符需要 int * 类型的参数,但我们传递的是 const int * 类型的参数。然而,这并不像赋值那样约束违反,因此不需要诊断。由于我们将错误类型的参数传递给该转换说明符的 scanf,因此行为未定义,这意味着编译器和运行时环境都不需要处理任何特定方式的情况。在这种情况下,您的实现更新了变量。在 testInteger was 存储在只读内存中的实现中,您可能会遇到段错误或其他运行时错误,或者变量可能根本没有更新。

,

VC 不会警告您,您必须添加 -Wall,我使用的是 Dev C 或 Geany。不过,这不是编译器错误,只是一个不受欢迎的输出。

,

我相信有些操作系统和编译器可以将常量变量存储到只读内存中,但我也相信大多数情况下都不会这样做。这更像是一种让编译器知道“如果我试图错误地更改此变量的方法,我希望您警告我”,但编译器不会检查指向它的指针,而只会检查直接引用。>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。