C++复习3.C/C++常量的知识
C/C++常量的知识 20130918
语言的实现隐含着使用着一些常量,如初始化全局变量静态变量,另外还有一些我们不曾感觉到的变量:函数地址(也就是函数名称), 静态数组的名字,字符串常亮的地址。常量可以分为:字面常量,符号常量,契约性常量,bool常量,枚举常量
一、常量的种类
1.字面常量是保存在程序的符号表中而不是一般的数据区(实际上是静态存储区而不是栈中),这些符号是只读的,是一种访问保护机制。我们无法获取这些常量的地址。而且对于字符串常量,我们不可以使用字符串的地址修改他们的值
char * p= “yang”’; 相当于 const char *p = “yang”;
2.符号常量
使用#define定义的宏常量和使用const定义的常量。#define是预编译的指令,它定义的宏常量在进入编译阶段就已经被替换成所代表的字符串常量了,因此宏定义指令本质上是字面常量。在C语言中的const定义的常量是不可以修改的,因此会给他分配存储空间。但是在C++中的const定义的常量要分情况:对于基本数据类型的常量,编译器会把它放到符号表中二部分配存储空间,对于ADT/UDT的const常量则需要分配存储空间。
我们可以取一个const符号常量的地址:对于基本数据类型的const常量,编译器会重新在内存中创建他的一个拷贝,通过其地址访问到的就是这个拷贝而不是原始的符号常量;而对于构造类型的常量,实际上他是编译的时候不允许修改的变量,因此我们如果绕过编译器的静态类型安全检查机制,就可以在运行期间修改他的内容了。
const long lng = 10;
long *p1 = (long *) & lng;
*p1 = 10000;
cout << "pl " << p1 << endl;
cout << "&lng" << &lng << endl;
cout <<"*pl : "<< *p1 << endl;
cout << "lng:" << lng << endl;
class Integer{
public:
Integer():m_lng(100){}
long m_lng;
};
const Integer val;
Integer *pInt = (Integer*) &val;
(*pInt).m_lng = 999999;
cout << "*pInt: " << pInt->m_lng << endl;
cout << "val: " << val.m_lng << endl;
const只是在编译的时候(代码级语言层面)强类型的安全检查机制的一种手段,帮助编码人员发现无意中修改的代码,而在运行的时候无法阻止恶意的修改,也就是说的“防君子不防小人”。
从理论上说只要你掌握一个对象的指针(内存地址),我们就可以绕过编译器随意修改他的内容,除非该内存区域受到操作系统的保护。也就是说C++并没有提供对指针有效的静态检查,而是把它丢给了OS,这正是指针的危险所在。
C语言中const符号常量默认是外连接的(分配存储),所以我们不可以在两个编译单元中同时定义一个同名的const符号常量,或者是把一个const符号常量定义房子啊一个头文件中而在多个编译单元中同时包含该头文件。但是在C++标准中,默认是内连接的,因此可以定义在头文件中。当在不同的编译单元中包含该头文件,编译器会默认他们是不同的符号常量,因此每一个编译单元独立编译时会给他们分别分配存储单元,而在连接的时候进行常量合并。
3.契约常量
未使用关键字const但是被看做一个const对象的
void ReadValue(cons tint & num){ cout << num ;}
int main(){ int n = 999; ReadValue(n);}
4.枚举常量
C/C++的构造类型enum实际上是用来定义一些相关常量的集合。并且规定枚举常量的值是可以扩展的,并非受限一般的整数类型。
enum Gigntic{ SMALL = 10, MID = 100, BIG = 1000};底层如何实现根据C/C++提供山的不同实现而有所不同。
5.正确定义符号常量
#define MAX 100
const int MAX = 100;
const float PI = 3.1415926;
C++ 中的需要将对外公开的长濑那个放倒头文件中,不需要对外工卡的常量放在定义文件的头部,便于管理,将不同模块的常量放在一个公用的头文件中。
6.const #define
const和#define都可以用于定义常量,但是const有一下的优点:
const常量是由数据类型的,#define是没有数据类型的,编译器可以对前者进行静态类型的安全检查,后者只是字符串的替换工作,没有安全类型的检查,并且在字符串替换的时候肯呢过产生意料之外的错误(边际效应);
有些集成化调试工具可以对const常量进行调试,但是不可以对#define进行调试。
7.类中的常量
常量尽在类中有效,犹豫#define定义的宏常量是全局的,不能达到目的,所以在class 中山hi也难怪const修饰数据成员来实现。const确实存在,但是其含义不是我们所期望的。非静态const数据成员是属于每一个对象的成员,只是在某个对象的生存期限内是常量,而对于整个类来说他是可以变化的,除非是static const常量
在class中不能够初始化非静态的const成员,因为在来创建之前,编译器是无法知道size的值是什么
class A{ const ing SIZE = 100;// error ,企图在类声明中初始化const数据成员
int array[SIZE]; /error 位置size的value
}
非静态的const数据成员初始化只能够在构造函数的初始化列表中进行
Class A{
public:
const int SIZE;
A int (size): SIZE(size){}
}
对于整个class的常量,const就不起作用了,应该使用enum中的美剧常量来实现。枚举常量不会占用对象的存储空间,在编译的时候就会全部赋值而且是定义的一个匿名的枚举类型,但是不可以定义float
class A{
enum {SIZE1 = 100, SIZE2 = 1000};
int array1[SIZE1]; in array2[SIZE2];
}
另外一种方法就是使用static const
class MyClass{
public:
static const int SIZE = 100;
MyClass(){}
static int getSize(){
return SIZE;
}
};
MyClass val;
cout << val.SIZE << endl;
cout << MyClass::SIZE << endl;
8.实际应用中如何定义常量
C程序中的使用方法:
定义在标准的头文件中CommonDef.h
static cons tint MAX_LENGTH = 1024;
然后每一个使用它的编译单元 #include该头文件即可,或者在头文件中使用该宏定义。
在头文件中将符号常量声明为extern 如:
extern const int MAX_LENGTH;
并且在某个源文件中定义一次
const int MAX_LENGTH = 1024; 然后每一个使用它的编译单元#include上述的头文件即可。
对于enum类型,每一个使用它的编译单元#include该头文件即可。
对于C++程序:
1).在某个头文件中直接在某个名字空间中或者全局名字空间中定义符号常量并且初始化,有没有static无所谓。
//CommonDef.h
const int MAX_LENGTH = 1024;
每一个编译单元直接使用include该头文件。
2).在某个公用的头文件中并且在某个命名空间下,或者是全局名字空间中将常量声明为extern
//CommonDef.h
extern const int MAX_LENGTH ;
并且在对应的源文件中定义一次
const int MAX_LENGTH = 1024;
每一个编译单元include头文件即可
3).整形常量,在某个enum中定义,直接使用include该头文件
4).定义为某一个公用类 static const 数据成员并且初始化,或者是类内的枚举类型。
Utility.h
class Utility{
public:
static const int MAX_LENGTH;
enum{ TIME_OUT = 10};
}
//Utility.cpp
const int Utility::MAX_LENGTH = 1024;
C++复习3.C/C++常量的知识的更多相关文章
- Java中常量小知识
常量分类:常量分为静态常量,非静态常量(全局常量),局部常量 静态常量:要么定义的时候赋初值,要么在静态代码块中赋值 非静态常量:要么在定义的时候赋初值,要么在代码块中赋值 局部常量:可以在定义时赋初 ...
- 【java】由equals和==的区别引出的常量池知识
equals和==的区别,百度查到的结果大都是:equals比较的是值,==比较的是引用地址. String str1 = "abc"; String str2 = "a ...
- 复习笔记——1. C语言基础知识回顾
1. 数据类型 1.1 基本数据类型 整型:int, long,unsigned int,unsigned long,long long-- 字符型:char 浮点型:float, double-- ...
- 浅谈C#中的 async await 以及对线程相关知识的复习
C#5.0以后新增了一个语法糖,那就是异步方法async await,之前对线程,进程方面的知识有过较为深入的学习,大概知道这个概念,我的项目中实际用到C#异步编程的场景比较少,就算要用到一般也感觉T ...
- JavaScript 常量定义
相信同学们在看见这个标题的时候就一脸懵逼了,什么?JS能常量定义?别逗我好吗?确切的说,JS当中确实没有常量(ES6中好像有了常量定义的关键字),但是深入一下我们可以发现JS很多不为人知的性质,好好利 ...
- 驱动实现led,pwm和中断基础知识
2015.4.8星期三 晴天 今天老师讲的内容是内核编写led和pwm驱动,实现花样灯和放歌的功能.理解应用和驱动的对接,最后自己实现了在放歌的时候根据歌曲的节奏亮灭一个小灯,应为两个独立的驱动都已经 ...
- Java基础知识系列——String
最近晚上没有什么事(主要是不加班有单身),就复习了一下Java的基础知识.我复习Java基础知识主要是依据Java API和The Java™ Tutorials. 今天是第一篇,复习了一下Strin ...
- 转载 Deep learning:一(基础知识_1)
前言: 最近打算稍微系统的学习下deep learing的一些理论知识,打算采用Andrew Ng的网页教程UFLDL Tutorial,据说这个教程写得浅显易懂,也不太长.不过在这这之前还是复习下m ...
- Deep learning:一(基础知识_1)
本文纯转载: 主要是想系统的跟tornadomeet的顺序走一遍deeplearning; 前言: 最近打算稍微系统的学习下deep learing的一些理论知识,打算采用Andrew Ng的网页教程 ...
随机推荐
- split_lzo_lib.sh
split_lzo_lib.sh #!/bin/sh#输入文件名filename=$1#分割文件大小filesize=4096#输出库文件名libname="lib"$(echo ...
- EasyUI 的DataGrid中DateTime的格式化问题
想必用过EasyUI的朋友们都应该会遇到这样的情况吧:(下图) 在EasyUI中DataGrid中如果要显示DateTime的时间时候,便会显示上图这样的格式,很明显,这里的格式不会是我们想要的,我们 ...
- Spring Boot+BootStrap fileInput 多图片上传
一.依赖文件 <link rel="stylesheet" type="text/css" th:href="@{/js/bootstrap/c ...
- LookupEdit已选过后如何删除值使其空白
属性Properties 的AllowNullInput 设置为True,就可以删除了. 当选择值后,按下control+delete就可以变为空白
- 通过自动回复机器人学Mybatis笔记:接口式编程
[接口式编程]尚未遇见Spring --> 代码量反而增加 1.增加约定,减少犯错的可能(不用直接去写字符串 修改点1:命名空间 修改点2:增加接口,方法名与配置文件中的id对应 package ...
- Linux安装ftp组件vsftpd
1 安装vsftpd组件 安装完后,有/etc/vsftpd/vsftpd.conf 文件,是vsftp的配置文件. [root@bogon ~]# yum -y install vsftpd 2 添 ...
- [BZOJ1996] chorus合唱队
Description Input Output Sample Input 4 1701 1702 1703 1704 Sample Output 8 HINT 区间$dp$,首先每个点被放入队伍时队 ...
- jQuery实现输入框提示,当获取焦点时提示消失,当失去焦点时内容为空则显示提示,否则保留输入信息
首先看效果 默认状态下 获取焦点状态下 什么也没输入,离开 有输入离开 输入默认值离开 代码 <!DOCTYPE html> <html> <head> <m ...
- SpringBoot中使用log4j日志
一:引入jar包 使用SpringBoot创建项目的时候,pom文件引入了spring-boot-starter,其中包含了spring-boot-starter-logging,该依赖内容就是Spr ...
- QT 样式表实例
目标:实现button的圆角效果及背景颜色,鼠标滑过颜色变亮,鼠标点击颜色变重. 总体思路首,先根据需要及样式规则新建.qss文件,然后在代码中将文件引用并应用样式. 具体过程如下: 1在项目当前目录 ...