1 C中的const
C中const
修飾的變量是只讀變量,在使用const
關鍵字聲明定義變量時會給該變量分配內存空間。
const
修飾的全局變量默認是外部鏈接的,即其它源文件可以直接使用該變量。
const
修飾的局部變量存儲在棧區中,不能通過變量名直接修改該變量的值,但是可以通過指針的方式修改該變量對應的值,從某種意義上來說,C中const
修飾的變量不是真正意義上的常量,可以將其當作一種只讀變量。
C中const示例:
// fun.c
// c中const修飾的全局變量默認是外部鏈接的
const int num = 100; // a的本質是只讀的變量,存放在文字常量區(內存空間只讀)
// main.c
#include <stdio.h>
// 對fun.c中的a進行聲明(不要賦值)
extern const int num;
void test()
{
printf("num = %d\n", num);
// num = 200; // error: assignment of read-only variable 'num'
}
int main(int argc, char *argv[])
{
test();
return 0;
}
#include <stdio.h>
void test()
{
const int data = 200; // 局部只讀變量,通過指針的形式修改data變量的值
printf("data = %d\n", data); // 200
int* p = (int*)&data;
*p = 300;
printf("data = %d\n", data); // 300
}
int main(int argc, char *argv[])
{
test();
return 0;
}
總結:
-
const
修飾全局變量時,該變量存儲在文字常量區(只讀),不能通過指針的方式修改其內容 -
const
修飾局部變量是,該變量存儲在棧區中(可讀可寫),通過指針的方式可以修改其內同
2 C++中的const
C++中const
修飾的變量不需要創建內存空間,比如定義常量const int data = 10;
,C++會在一張符號表中添加name
為data
,value
為10的一條記錄,如下圖所示:
既然,const
修飾的變量沒有內存空間,所以在C++中const
修飾的變量才是真正意義上的常量。
C++中定義聲明的全局常量是內部鏈接的,只能作用於當前的整個文件中,如果想讓其它源文件對該常量進行訪問的,必須加extern
關鍵字將該常量轉換成外部鏈接。
在C++中,是否為const
常量分配內存空間依賴於如何使用,以下情況會對常量進行內存空間的分配:
- 對
const
常量取地址時 - 使用變量的形式初始化
const
修飾的變量時 const
修飾自定義數據類型(結構體、對象)時
C++中const示例:
// fun.c
// const修飾的全局變量,默認時內部鏈接,不能直接被其它源文件使用
//const int num = 100;
// 可以通過將num轉換成外部鏈接的方式,供其它源文件對num的訪問
extern const int num = 100;
// main.c
#include <iostream>
using namespace std;
extern const int num;
struct Person{
int num;
char name[32];
};
void test()
{
cout << "全局num = " << num << endl; // error: undefined reference to `num'
// 1. c++中對const修飾的基礎類型的變量不會開辟內存空間,只是將其放到符號表中
const int data = 100;
// data = 200; // error: 只讀
cout << "data = " << data << endl;
// 2. 對data取地址時,系統會給data開辟空間
int* p = (int*)&data;
*p = 2000;
cout << "*p = " << *p << endl; // 2000
cout << "data = " << data << endl; // 100
// 3. 通過變量的形式初始化 const修飾的變量,系統會為其開辟空間
int a = 200;
const int b = a; // 系統直接為b開辟空間,不會把b放入到符號表中
p = (int*)&b;
*p = 3000;
cout << "*p = " << *p << endl; // 3000
cout << "b = " << b << endl; // 3000
// 4. const修飾自定義類型的變量,系統會分配空間
const Person per = { 100, "viktor" };
// p1.num = 1000; // error
cout << "num = " << per.num << ", name = " << per.name << endl; // 100, viktor
Person* p1 = (Person*)&per;
p1->num = 2000;
cout << "num = " << per.num << ", name = " << per.name << endl; // 2000, viktor
}
int main(int argc, char *argv[])
{
test();
return 0;
}
總結:
- C++中,使用
const
定義聲明變量時,該變量會先放入到符號表中,不會開辟內存空間; const
修飾的全局變量默認是內部鏈接的;- 對
const
修飾的變量進行取地址操作,系統會對該變量開辟空間; - 使用其它的變量對
const
修飾的變量進行初始化時,系統會對該變量開辟空間; const
修飾自定義的數據類型,系統為自定義數據開辟空間。
3 C/C++中const異同總結
3.1 const修飾全局變量
全局變量存儲在只讀的文字常量區,所以C/C++中const
修飾的全局變量都不可以更改變量對應的內容。
C中const
修飾的全局變量默認是外部鏈接的,而C++中默認的是內部鏈接,如果想使得其變為外部鏈接可以在const
修飾的全局變量前加extern
關鍵字。
3.2 const修飾局部變量
const
在修飾基礎數據類型的局部變量時,在C中會給該變量在棧中開辟內存空間,可以通過指針的方式修改變量的內容;而C++對於const
修飾基礎類型的變量是在符號表中添加一條記錄,不會在棧中開辟空間,所以不能通過指針的方式修改變量的值。
C++中對const
修飾的局部變量是在如何使用的情況下才分配內存,如果對const
修飾基礎數據類型的局部變量進行取地址操作,會對變量分配內存;使用一個變量初始化const
變量時會分配內存;const
修飾的自定義數據類型(結構體、對象)會分配內存。
4 const和#define
在舊版本C中,如果想創建一個常量,必須使用預處理器#define MAX 1024;
。使用宏定義的MAX
對於編譯器來說不知其的存在,因為在程序預處理的過程中,所有的MAX
已經被替換為1024,於是MAX
並沒有將其加入到符號表中。
如果使用這個常量獲得一個編譯錯誤信息時,可能會帶來一些困擾,因為這個信息可能會提到1024,但是並沒有提到MAX
。
此外MAX
如果被定義在另外一個頭文件中,當前可能並不知道1024代表什么,也許解決這個問題要花很長時間。解決辦法就是用一個常量替換上面的宏。
const
和#define
的區別:
const
有類型,可進行編譯器類型安全檢查。#define
無類型,不能進行類型檢查
示例:
// 宏沒有類型,const有
#define MAX 1024
const short my_max = 1024;
void func(short i)
{
cout << "short函數" << endl;
}
void func(int i)
{
cout << "int函數" << endl;
}
void test()
{
func(MAX); // int函數
func(my_max); // short函數
}
const
有作用域,而#define
不重視作用域,默認定義出到文件結尾。如果定義在指定作用域下有效的常量,那么#define
就不適用
示例:
// 宏的作用域是當前的整個文件,const的作用域以定義的情況決定
void my_func(void)
{
// 作用范圍是當前復合語句
const int my_num = 10;
// 作用范圍是當前位置到文件結束
#define MY_NUM 10
}
void test()
{
// cout << "my_num = " << my_num << endl; // err 不識別
cout << "MY_NUM = " << MY_NUM << endl; // ok
}
const
可以作為命名空間的成員,而如果將宏作為命名空間的成員,失去了命名空間的意義,因為宏作用於當前的文件,而不是只屬於某個命名空間的
5 總結
const
由C++采用,並加進標准C中,盡管它們很不一樣,在C中,編譯器對待const
如同對待變量一樣,只不過帶有一個特殊的標記,意識是”你不能改變我“。在C++中定義const
時,編譯器為它創建空間,所以如果兩個不同文件定義多個同名的const
,鏈接器將發生鏈接錯誤。簡而言之,const
在C++中用的更好。
在C++中盡量使用const
來替換宏定義,避免不必要的麻煩。
另外在C++中可以使用變量定義數組。對於C,在支持C99標准的編譯器中,可以使用變量定義數組。
示例:
#include <iostream>
using namespace std;
void test()
{
int a = 10;
int arr[a];
int i = 0;
for(; i < 10; i++)
arr[i] = i;
i = 0;
for(; i < 10; i++)
cout << arr[i] << " ";
cout << endl;
}
int main(int argc, char *argv[])
{
test();
return 0;
}