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

scanf()是否更新常量变量?,c,constants,scanf,C,Constants,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

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', the value of the variable 'testInteger' is %d.\n", testInteger);

    return 0;
}
我想知道为什么scanf会更新'testInteger'常量变量的值。

是的,它应该具有常量值,但它不能神奇地保证它

您获取了一个const int*类型变量的地址,它只不过是一个指向某个内存的数字。然后,通过将其传递给scanf,您违反了合同,您没有收到任何警告吗?您是否使用-Wall进行编译?:它被用作常规int*指针。

是的,它应该具有常量值,但它并不能神奇地保证它

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

尝试编写常量对象是未定义的行为。可能有效,可能无效,可能崩溃,可能

const int testInteger = 0;
scanf("%d", &testInteger); // UB
试图写入常量对象是未定义的行为。可能有效,可能无效,可能崩溃,可能

const int testInteger = 0;
scanf("%d", &testInteger); // UB

VC没有警告您,您必须添加-Wall,我使用的是devc或Geany。这不是一个编译器错误,只是一个不理想的输出。

VC没有警告您,您必须添加-Wall,我使用的是devc或Geany。这不是一个编译器错误,只是一个不理想的输出。

C依赖硬件来强制常量变量的只读性。大多数计算机硬件只能强制执行称为页的大块内存的只读性,而不是单个整数大小的变量

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

如果将testInteger的声明更改为static const int testInteger,或者将其声明为全局,则会将其分配到为常量变量保留的特殊内存区域中,即内存块不可写入的只读数据段,当您的程序试图写入testInteger时,它将在scanf内部崩溃


无论如何,将const数据对象声明为globals/with static storage duration几乎总是正确的,因此这种硬件限制在实践中并不是什么大问题。事实上,这是一件大事,但原因完全不相关。

C依靠硬件强制执行常量变量的只读性。大多数计算机硬件只能强制执行称为页的大块内存的只读性,而不是单个整数大小的变量

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

如果将testInteger的声明更改为static const int testInteger,或者将其声明为全局,则会将其分配到为常量变量保留的特殊内存区域中,即内存块不可写入的只读数据段,当您的程序试图写入testInteger时,它将在scanf内部崩溃


无论如何,将const数据对象声明为globals/with static storage duration几乎总是正确的,因此这种硬件限制在实践中并不是什么大问题。实际上,这是一件大事,但原因完全无关。

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

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

这里有几个问题

首先,const only意味着这个东西可能不是赋值运算符的目标,而不是必须存储在只读内存中。仅当常量限定变量是赋值运算符的目标时,编译器才需要发出诊断


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

这里有几个问题

首先,const only意味着这个东西可能不是赋值运算符的目标,而不是必须存储在只读内存中。仅当常量限定变量是赋值运算符的目标时,编译器才需要发出诊断


其次,scanf的%d转换说明符需要int*类型的参数,但我们正在传递const int*类型的参数。但是,这并不像赋值那样违反约束,因此不需要诊断。因为我们为转换说明符向scanf传递了错误类型的参数,所以行为是未定义的,这意味着编译器和运行时环境都不需要以任何特定方式处理这种情况。在本例中,您的实现更新了变量。在testInteger存储在只读内存中的实现中,可能会出现SEGFULT或其他运行时错误,或者变量可能根本无法更新。

将常量变量的地址传递给scanf会导致未定义的行为。任何事情都可能发生,包括更新它。MS Visual C确实对此发出警告:“scanf”:格式字符串“%d”需要“int*”类型的参数,但是变量参数1的类型是“const int*”,你不使用const,因为常量变量没有改变。答案:当你将一个const变量传递给scanf.const时,你对编译器撒了谎。基本上,我保证不会尝试修改它。这并不意味着把它放在只读存储器中。这并不意味着,我需要一个保证,如果我不小心违背了承诺,我会可靠地收到一条错误消息来提醒我。所以你许下了诺言,却违背了诺言,而且。。。你侥幸逃脱了。C有时也是这样-/将常量变量的地址传递给scanf会导致未定义的行为。任何事情都可能发生,包括更新它。MS Visual C确实对此发出警告:“scanf”:格式字符串“%d”需要“int*”类型的参数,但是变量参数1的类型是“const int*”,你不使用const,因为常量变量没有改变。答案:当你将一个const变量传递给scanf.const时,你对编译器撒了谎。基本上,我保证不会尝试修改它。这并不意味着把它放在只读存储器中。这并不意味着,我需要一个保证,如果我不小心违背了承诺,我会可靠地收到一条错误消息来提醒我。所以你许下了诺言,却违背了诺言,而且。。。你侥幸逃脱了。C有时也是这样-/细节如果存储在只读内存中,则会出现segfault或类似的运行时错误。或者可能没有报告错误。首先,const只意味着这个东西可能不是赋值操作符的目标-这是误导。这个东西可能不是赋值操作符的目标,它是关于const强制执行的为数不多的事情之一,但它并不是const的全部含义。尝试修改常量声明变量的值是未定义的行为,无论如何尝试。详细信息。。。如果存储在只读内存中,则会出现segfault或类似的运行时错误。或者可能没有报告错误。首先,const只意味着这个东西可能不是赋值操作符的目标-这是误导。这个东西可能不是赋值操作符的目标,它是关于const强制执行的为数不多的事情之一,但它并不是const的全部含义。尝试修改常量声明变量的值是未定义的行为,无论如何尝试。