返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言中的const如何保证变量不被修改
  • 397
分享到

C语言中的const如何保证变量不被修改

2024-04-02 19:04:59 397人浏览 泡泡鱼
摘要

这小段文章要理清楚的是,在C语言中,const是如何保证变量不被修改的? 我们可以想到两种方式: 第一种,由编译器来阻止修改const变量的语句,让这种程序不能通过编译; 第二种,由

这小段文章要理清楚的是,在C语言中,const是如何保证变量不被修改的?

我们可以想到两种方式:

第一种,由编译器来阻止修改const变量的语句,让这种程序不能通过编译;

第二种,由操作系统来阻止,即把const 的内存地址访问权限标记为“只读”,一旦运行中的程序试图修改它,就会产生异常,终止进程。

上面想到的这两种方式,都能达到让某一变量的值不被修改的目的,那么究竟是哪一种呢?我们写两个例子来看一看。

先来看一个简单的例子,源文件const.c:


#include <stdio.h>
const int a=10;
int main()
{
 int *p=&a;
 printf("initial: %d\n",a);
 *p=1;
 printf("modified: %d\n",a);
 return 0;
}

编译,会收到一个 warning:

$ GCc -o const1 const1.c
const.c: In function ‘main':
const.c:7:12: warning: initialization discards ‘const' qualifier from pointer target type [-Wdiscarded-qualifiers]
     int *p=&a;

忽略之,运行程序:

$ ./const1
initial: 10
Segmentation fault (core dumped)

运行出错了,报错是“segmentation fault”,即“段错误”,它是在提醒我们,程序中用错误的权限访问了内存某区域。这说明,操作系统把变量$a$加载到了一段只读内存区域之中,因此对该区域地址的写操作将引发异常,这是由操作系统的内存保护机制决定的。

也就是说,在这段程序里,const的只读属性是由操作系统来实现的,而不是由编译器来实现的(编译器只抛出了warning,并没有阻止编译通过)。

这对吗?不完全对,我们来看另一个例子,源文件const2.c:


#include <stdio.h>
int main()
{
 const int a=10;
 int *p=&a;
 printf("initial: %d\n",a);
 *p=1;
 printf("modified: %d\n",a);
 return 0;
}

编译,还是收到同样的warning:

$ gcc -o const2 const2.c
const.c: In function ‘main':
const.c:6:12: warning: initialization discards ‘const' qualifier from pointer target type [-Wdiscarded-qualifiers]
     int *p=&a;

忽略之,运行程序:

./const2
initial: 10
modified: 1

咦?怎么成功运行了,而且a的值还被顺利修改了?

结合以上两个例子,我们可以得出以下推测:

const只是C语言中的一种对变量的修饰符,例子中的a,与其说是“常量”,不如说是“不打算修改的变量”。它只是语法上的一种声明,它的作用就是告诉编译器“我不想修改它”,因此编译器会从语法上检查程序中是否有修改它的语句(例如“a=1;”),一旦发现这种“违背初衷”的语句,就会报错阻止你。

然而,编译器所阻止的仅仅是对a这个符号对应值的修改而已,却并不阻止对这个地址的值的修改,源文件“const2.c”之所以能顺利通过编译且正常运行,就是因为它利用一个名字不叫a的指针指向它,从而绕过了编译器的语法检查。

打个比方,周树人的笔名叫鲁迅,警察只知道要抓鲁迅,这时候他就可以用一句“你们抓鲁迅跟我周树人有什么关系?”来骗过他们。

从这个角度来说,const的作用是靠编译器仅仅从语法检查来实现的,因此存在运行时的漏洞。

那么为什么“const1.c”就不能正常运行呢?

仔细看这两个源程序,区别仅仅在于,在“const1.c”中,a被声明为全局变量,而在“const2.c”中,它被声明为main函数中的一个局部变量。全局变量与局部变量的区别在于,前者会在程序开始运行之前就被加载,加载后会一直留在内存中,且加载的位置在数据区,直到程序退出;后者只有在运行到它时才会被加载,且加载的位置是运行时的栈帧,一旦超出作用于就会被回收。

因此,编译器会对被声明为全局变量的const int a进行优化,把它放到只读内存区内,这一内存区的权限是“read\ only”,权限信息由操作系统所维护的段表来保存,程序每访问某地址时,操作系统都会检测其访问权限是否合法。“const2.c”中企图用“写”的方式来访问“只读”的段,自然会报出“segment fault"的错了。

从这个角度来说,当a是全局变量时,编译器把原本只是“不打算修改的变量”优化成了“真正的常量”,然后交给操作系统去维持其不变属性。

综上所述,C的初衷只是让编译器去保证$const$的不变属性,这一属性有漏洞(可以用指针去骗过编译器修改它),所以当const修饰的对象是全局变量时(全局变量很重要,因为很多源文件都要访问它,牵一发而动全身,所以不应轻易更改),编译器知道自己的能力有限,只能管得了编译,管不了运行时如何,所以优化了语句把它编程真正的常量,让操作系统的内存保护功能来履行这一职责。

这一优化,并不是C规定的,而是编译器厂商出于实际应用的考虑作出的选择。

以上,是我根据编译器和程序运行时的行为所做的推测,这一思路并不妥当,只是我在编程时遇到了上述两个例子的困惑,又没找到说得很清楚的资料,所以就写出来了,若要进一步验证,应该查看编译后的可执行文件分段情况,我偷了个懒没看,暂时放在这里。

如果推测不正确,希望有前辈指出。

总结

到此这篇关于C语言中const如何保证变量不被修改的文章就介绍到这了,更多相关C语言const变量不修改内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言中的const如何保证变量不被修改

本文链接: https://lsjlt.com/news/122978.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C语言中的const如何保证变量不被修改
    这小段文章要理清楚的是,在C语言中,const是如何保证变量不被修改的? 我们可以想到两种方式: 第一种,由编译器来阻止修改const变量的语句,让这种程序不能通过编译; 第二种,由...
    99+
    2024-04-02
  • C语言中const保证变量不被修改的方法有哪些
    小编给大家分享一下C语言中const保证变量不被修改的方法有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在C语言中,const是如何保证变量不被修改的?我们...
    99+
    2023-06-14
  • C++中如何修改const变量你知道吗
    目录一、结论二、分析1.g++ 2.devc++3.VC++6.0(1)添加volatile修饰符时,输出结果(程序代码同上):(2)无volatile修饰符时。输出结果:...
    99+
    2024-04-02
  • c语言和c++语言中const修饰的变量区别浅析
    目录c:修饰全局变量:修饰局部变量:c++:修饰全局变量:修饰局部变量:总结:在c语言中:在c++语言中:总结c: 修饰全局变量: 用const修饰的全局变量是没有办法直接修改的,间...
    99+
    2024-04-02
  • c语言空字符常量如何修改
    C语言中的空字符常量是’\0’。要修改空字符常量,可以直接赋予它一个新的字符值,例如: char null_char = '...
    99+
    2024-03-13
    c语言
  • c语言中全局变量如何定义
    在C语言中,全局变量可以在函数外部定义。它们的作用域从变量定义的位置开始,直到文件的末尾。全局变量在整个程序中都是可见的,可以被任何...
    99+
    2023-09-29
    c语言
  • c语言中字符串变量如何定义
    在C语言中,字符串变量可以通过以下几种方式定义:1. 使用字符数组来定义字符串变量:```cchar str[100]; // 定义...
    99+
    2023-09-29
    c语言
  • c语言中如何修改文件内容
    要修改文件内容,可以使用标准库中的文件操作函数来实现。以下是一个示例代码,演示如何打开一个文件、将内容写入文件并关闭文件: #inc...
    99+
    2024-04-02
  • c语言中变量未初始化如何解决
    在C语言中,变量未初始化可能会导致程序出现不确定的行为和错误。为了解决这个问题,可以采取以下几种方法: 显式初始化:在声明变量的...
    99+
    2024-02-29
    c语言
  • 如何Python语言元素中的变量
    这篇文章给大家介绍如何Python语言元素中的变量,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。作为一个程序员,可能经常会被外行人问到两个问题,其一是“什么是(计算机)程序”,其二是“写(计算机)程序能做什么”,这里我...
    99+
    2023-06-01
  • 如何分析C语言关键字中的void、const和return
    这篇文章将为大家详细讲解有关如何分析C语言关键字中的void、const和return,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。return首先我们弄清楚c语言内存分配的方式然后我们看一...
    99+
    2023-06-22
  • C语言中如何实现局部与全局变量
    这篇“C语言中如何实现局部与全局变量”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言中如何实现局部与全局变量”文章吧。C...
    99+
    2023-06-16
  • C语言如何得到一个变量的地址
    小编给大家分享一下C语言如何得到一个变量的地址,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!得到一个变量的地址typedef&n...
    99+
    2024-04-02
  • Go语言中的切片和变量有何不同?
    在 go 语言中,变量和切片是两种不同的数据结构,具有不同的特性和用法。变量存储单一值,而切片存储多个值并具有动态大小。变量具有固定大小并可以通过赋值分配,而切片是使用 make() 函...
    99+
    2024-04-02
  • 如何在python中修改作用域的变量
    如何在python中修改作用域的变量?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比,Pytho...
    99+
    2023-06-14
  • 详解如何在Golang中修改变量的值
    Golang是当今最为流行的编程语言之一,它具有简单易用、高效、安全等优点,使得它在应用开发领域里得到越来越广泛的应用。在程序开发过程中,我们经常需要改变变量的值,本文将介绍如何在Golang中改变变量的值以及相关的语法细节。一、变量的声明...
    99+
    2023-05-14
  • 如何修改C语言的默认存储位置
    C语言的默认存储位置是由编译器来确定的,通常是存储在计算机的主内存中。如果你想修改C语言的默认存储位置,可以通过以下方法来实现:1....
    99+
    2023-09-26
    C语言
  • c语言中使用了未初始化的局部变量怎么改
    c 语言中未初始化局部变量的改正方法有:1. 显式赋值;2. 指定初始值;3. 使用预处理器宏;4. 编译器选项。通过这些方法,可以确保局部变量在使用前被初始化,消除未定义行为的风险。 ...
    99+
    2024-05-10
    c语言
  • Go语言中的路径变量如何设置?
    在Go语言中,路径变量是一种非常有用的机制,它可以让我们在代码中引用文件路径时变得更加灵活。在本文中,我们将探讨Go语言中的路径变量是如何设置的,并且演示一些示例代码来帮助您更好地了解它们的使用。 在Go语言中,路径变量可以使用os模块中...
    99+
    2023-06-14
    shell ide path
  • c语言中字符串变量如何用指针指向第一位
    通过指针指向 c 语言字符串变量的第一位步骤如下:声明一个字符指针变量。将指针变量赋值为字符串变量的地址,可以使用取地址运算符 (&)。 如何用指针指向 C 语言字符串变量的第...
    99+
    2024-05-22
    c语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作