C中const 定义常量的使用
- 先看如下代码
#include <stdio.h>
#include <string.h> #define ARRSIZE(a) (sizeof(a)/sizeof(a[0]))
int main()
{
const int i = 10;
int *p = (int *)&i;
int a[i];
*p = 100; printf("%d\n", ARRSIZE(a));
printf("%d\t%d\n", i, *p);
return 0;
}我用gcc编译运行,上面这段简单的代码的输出结果是:100 # 这也是一个很奇怪的结果。100 100
这个结果说明了2个问题,1:可以用const变量作为数组大小;2:可以修改const变量的值。
但难道真是这样吗?又或者说,难道在不同机器,不同编译器下都这样吗?
并不尽然,首先这个程序在VC编译器下,不能通过,VC编译器不允许用const变量作为数组大小。即使把有关数组的给删掉,VC编译后的可执行文件不能执行,发生内存错误。这说明不可以修改const变量。
因此这个是与编译器有关的。
下面要思考的是:为什么gcc编译器能允许这事发生,而VC不允许。对上面的代码略做修改,将const int i = 10放到main函数外面去。#include <stdio.h>
#include <string.h> #define ARRSIZE(a) (sizeof(a)/sizeof(a[0]))
const int i = 10;
int main()
{
int *p = (int *)&i;
int a[i]; printf("%d\n", ARRSIZE(a));
*p = 100;
printf("%d\t%d\n", i, *p);
return 0;
}这时gcc编译通过,运行出现段错误。段错误是经典错误,表明访问了不该访问的段。因此这说明全局的const变量不能修改;局部的const能修改。
作如下推测:gcc下,全局的const变量存储于只读的数据段,因此肯定不能修改。局部的const存储在堆栈段,堆栈段是可读可写的;因此不能避免程序员去修改const。
虽然局部const在堆栈,且堆栈可写,但如下方式却行不通:const int i = 10;i = 100; # 这里的错误是编译错误。因此编译器不允许你对局部const变量[直接]修改,它能够识别你在修改const变量。但正如前面的程序,你只要将局部const变量的地址赋给指针,就能骗过编译器了。而在VC下,const变量总是在只读数据段里。
这时再来看数组#include <stdio.h>
#include <string.h> #define ARRSIZE(a) (sizeof(a)/sizeof(a[0]))
const int i = 10;
int a[i]; // 将数组拿到main的外面来
int main()
{
printf("%d\n", ARRSIZE(a));
return 0;
}这时会有编译错误:error: variably modified ‘a’ at file scope如果将"int a[i]"放到main函数里,则正确。
我还不太清楚这样的具体原因。这里我只能大致得出结论是:不能用const变量来作为数组大小。至于为什么将"int a[i]"放到main函数里时没有错误,我并不清楚,我看了下汇编码,发现gcc对这种情况进行了一些特殊的处理,并不是简单的分配堆栈空间,但更细致的原因,我并未深入研究。
另外在VC下,是不能用const变量来作为数组大小的,不管是局部还是全局的const。
因此不要试着去修改const变量,也不要用const变量来作为数组大小
C中const 定义常量的使用的更多相关文章
- php中const定义常量
const 常量 1.在定义时必须被初始值,2.前面不加任何修饰符3.变量名字母一般都大写4.常量可以被子类继承5.一个常量是属于一个类的,而不是某个对象的 作用:当某些值是固定不变的,就用const ...
- PHP中define()和const定义常量的区别
在PHP中可以通过define()和const两种方式定义常量可是在开发中我们应该什么时候用define()定义常量,什么时候用const定义常量? 这两种方式定义常量的主要区别是什么? 从5.3版本 ...
- 在php中define和const定义常量的区别
define和const都可以用来定义常量,但是const定义常量的时候大小写敏感,而define可以通过设置第三个参数为true的时候来取消大小写敏感! 如图: 引用地址:点这里
- PHP 中 define() 和 const 定义常量时的区别
自 PHP 5.3.0 起,有两种方式定义常量,使用 const 关键字或者 define() 函数: 1 2 const FOO = 'BAR'; define('FOO', 'BAR'); 这 ...
- C++ —— 非类中使用const定义常量的初始化,以及#define和typedef的区别
总结一下在非类中使用const关键字定义常量时的初始化问题,亲测VS2015.顺便记录#define宏和typedef的区别. 1 首先对const声明的常量的初始化做简单小结: , w2 = , w ...
- 为什么很多人使用#define而不是const定义常量
众所周知,C语言一开始只有#define,C程序员用#define定义符号常量.但后来ANSI C加入了const限定符,而const应该比#define更好,为什么现在的C程序员还在大量使用#def ...
- iOS define 宏定义 和 const定义常量区别
const const 是c++中的修饰符. c++中常用来定义常量,修饰左值. #define 宏定义语句, 在预处理阶段直接做文本替换,不做类型检查. 它们之间的最大区别: 1. 对于co ...
- 关于java中接口定义常量和类定义常量的区别
/** * * @author YZJ * @Description java中定义常量的最佳方法 */ public final class Contants{ /** * @Description ...
- js 中const 定义的值是否能更改
const定义的基本类型不能改变,但是定义的对象是可以通过修改对象属性等方法来改变的. 1. const aa=trueaa=falseconsole.log(aa)VM1089:2 Uncaught ...
随机推荐
- libevent 和 libev 提高网络应用性能
构建现代的服务器应用程序需要以某种方法同时接收数百.数千甚至数万个事件,无论它们是内部请求还是网络连接,都要有效地处理它们的操作.有许多解决方 案,但是 libevent 库和 libev 库能够大大 ...
- 一步步实现windows版ijkplayer系列文章之六——SDL2源码分析之OpenGL ES在windows上的渲染过程
一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...
- 配置mysql5.5主从复制、半同步复制、主主复制
mysql主服务器 192.168.8.40 mysql从服务器 192.168.8.41 全新配置过程(主和从数据库都没有数据): 主从复制主服务器设置: 1.改server-id 2.启 ...
- Ex 6_3 修建酒店所获得的利润..._第五次作业
假设profit[i]为在前i个位置修建酒店所获得的最大利润,当i=0时,profit[0]=0.当i>0时,若j为上一个满足m[i]-m[j]k的位置.若profit[i-1]>prof ...
- js实现星级评分效果(非常规5个li代码)
1. 前言 此方案受到JS单行写一个评级组件启发,自己写了一个简单Demo. 功能有正常滑动,动态显示实心星星个数:当点击确认,则保持当前的实心星星个数:再移动时未点击,则离开后还是保持之前的状态. ...
- 重装windows系统后配置Anaconda
给电脑换了系统,十分担心anaconda需要重装.还好以下方法完美解决.(同是win10 64位) 原始anaconda安装路径:D:\ProgramData\Anaconda3 (不能有空格哦) ...
- LeetCode(41):缺失的第一个正数
Hard! 题目描述: 给定一个未排序的整数数组,找出其中没有出现的最小的正整数. 示例 1: 输入: [1,2,0] 输出: 3 示例 2: 输入: [3,4,-1,1] 输出: 2 示例 3: 输 ...
- java.util.Random 类
//: object/ForEachFloat.java package object; import java.util.Random; public class ForEachFloat { pu ...
- spoj227 树状数组插队序列问题
插队问题和线段树解决的方式一样,每个结点维护值的信息是该节点之前的空位有多少,然后从后往前插点即可 注意该题要求输出的是从左往右输出每个士兵的等级,即问士兵最后排在第几个位置 /* 树状数组维护前i个 ...
- 【【C++ Primer 第15章】 虚析构函数
学习资料 • C++中基类的析构函数为什么要用virtual虚析构函数 虚析构函数 1. 正文 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏.具体地说,如果派生类中申请了内存空 ...