一個用vue做的網(wǎng)站軟文范例大全500
文章目錄
- 前提
- 正文
- 多重定義
- extern關鍵字
- 使用static
- static 全局變量(在.cpp文件中定義)
- static變量存放在哪里
- static變量可不可以放在.h文件中
- static 函數(shù)
- static局部變量
- static 成員變量
- static 成員函數(shù)
- 總結
- 參考鏈接
前提
好吧,八股,我又回來了。這次想探究下static
關鍵字,因為用到過,同時對下面的有些問題,還不是很清楚:
- static變量都有什么
- static關鍵字的作用
正文
在開始研究static
之前,我想先引導幾個問題,這幾個問題對接下來理解static
有一定的作用。
多重定義
有test.h, test.cpp, main.cpp
三個文件如下:
/*=====test.h=====*/
#ifndef TEST_H_
#define TEST_H_int a = 5; /*=======這是重點======*/
void print();#endif
/*=====test.cpp=====*/
#include"test.h"
#include<iostream>void print()
{std::cout<<"hello, world\n";
}
/*=====main.cpp=====*/
#include <iostream>
#include "test.h"int main()
{print();std::cout<<"a: "<<a<<std::endl;
}
程序說明:在test.h
定義了一個int
的變量a
,我們想在main.cpp
中輸出這個a
,使用gcc
進行編譯。
運行結果:編譯出錯,出錯信息如下:
可以看到是鏈接期間的錯誤,多重定義。
我們分析下為什么會出現(xiàn)這個錯誤。
- 首先明白程序編譯的過程。 將源代碼編譯為可執(zhí)行文件有四個階段:預處理——>編譯——>匯編——>鏈接。預處理大概做的是:
define
定義的替換,include
文件的拷貝(比如說:main.cpp
中include了test.h
,編譯器會將test.h
的內容拷貝到main.cpp
中)等等;編譯大概做的是:將C++代碼編譯為匯編代碼;匯編大概做的是:將匯編代碼編譯為機器碼;鏈接大概做的是:將所有cpp文件編譯的機器碼合并為一個可執(zhí)行文件。大概來說就是這樣,詳細的大家可以自行百度。 - 這里我們先關注預處理階段。它會將
test.h
的內容拷貝到main.cpp
中,那么此時相當于已經(jīng)在main.cpp
中有了int a = 5
這個定義,有了a
這個變量(如果沒有a
這個變量,編譯器會直接報錯找不到a
)。然后對于test.cpp
,它也include了test.h
,所以test.cpp
中也有了int a = 5
這個定義,有了a
這個變量。 - 接下來兩個cpp分別進行編譯,匯編。
- 到了鏈接階段(上面的錯誤就發(fā)生在鏈接階段),它將
main.cpp
的機器碼和test.cpp
的機器碼合并到一起,但main
中a
的定義,test
中有a
的定義,所以就會出現(xiàn)多重定義的這個錯誤。
舉這個例子是想給大家說明程序編譯的過程。接下來我們使用extern
關鍵字改寫這個程序。
extern關鍵字
/*=====test.h=====*/
#ifndef TEST_H_
#define TEST_H_
void print();#endif
/*=====test.cpp=====*/
#include"test.h"
#include<iostream>int a = 5;
void print()
{a = a+1;std::cout<<"a: "<<a<<std::endl;
}
/*=====main.cpp=====*/
#include <iostream>
#include "test.h"
extern int a;
int main()
{a = a+1;std::cout<<"a: "<<a<<std::endl;print();
}
程序說明:在test.cpp
中定義一個全局變量a
,然后在main.cpp
中想使用這個變量a
,這里我們借助了extern
這個關鍵字,表明:這只是a
的聲明,它在其它地方定義(在test.cpp
中定義)。
運行結果:如下所示。
按照上面的分析過程,自已分析下。
使用static
我們見到的static大概有以下幾類:
- static 全局變量
- static 局部變量
- static 成員變量
- static 函數(shù)
- static 成員函數(shù)
static 全局變量(在.cpp文件中定義)
改寫代碼如下:
/*=====test.h=====*/
#ifndef TEST_H_
#define TEST_H_void print();
#endif
/*=====test.cpp=====*/
#include"test.h"
#include<iostream>
static int a = 5;
void print()
{a = a+1;std::cout<<"a: "<<a<<std::endl;
}
/*=====main.cpp=====*/
#include <iostream>
#include "test.h"
// extern int a; # 重點關注
int main()
{print();std::cout<<a<<std::endl;
}
程序說明:在test.cpp
中定義了一個static
變量a
,然后print()
函數(shù)使用了這個變量,最后在main.cpp
中調用print()
函數(shù)。
運行結果:
這里重點關注main.cpp
中注釋的這行代碼:extern int a
。從上面可知,extern
的作用是告訴編譯器我的這個a
只是聲明,你鏈接的時候在其它地方去找。
而一但我們使用static
來定義這個變量時,該變量就只在test.cpp
中可見(也就是對其它的cpp文件隱藏),這時如果我們在main.cpp
中使用extern
,編譯器還是找不到變量a
的定義。運行結果如下:
所以這就是static
的第一個作用:隱藏。static
聲明的全局變量只在該文件內可見,對其它文件是不可見的。
隱藏這個特點會帶來什么好處呢?
- 利用這一特點可以在不同的文件中定義同名變量,而不必擔心命名沖突。
明白這一點后,我們在來看一些小問題:
static變量存放在哪里
先來看看現(xiàn)代操作系統(tǒng)中一個進程的內存空間布局:
Text section: 存放二進制指令。
Data section: 存放非0初始化的靜態(tài)數(shù)據(jù)和全局變量。
BSS (Block Started by Symbol): 存放0初始化的靜態(tài)數(shù)據(jù)和全局變量,程序中沒有初始化的靜態(tài)數(shù)據(jù)會被初始為0并存放到這里。
Heap: 存放動態(tài)分配的數(shù)據(jù)。
Stack: 存放局部變量,函數(shù)參數(shù),指針等。
來吧,讓我們繼續(xù)。C++的內存分布(有的人說C++沒有標準的內存分布)和上面的基本一致,只不過顯式指出了有一個**只讀數(shù)據(jù)區(qū)(.rodata)**用來存放全局常量數(shù)據(jù)(const),如下:
回歸正題,我們采用一些方法來確認static
全局變量存放在**.bss section**(未初始化)和**.data section**(初始化)。
先來確定初始化的static
變量存放在.data
中。
有以下代碼:
static int variable_a=10; // 全局static變量,已初始化為10
int main()
{}
這里要借助objdump這個命令。objdump 是一個功能強大的命令行工具,用于顯示二進制文件(如可執(zhí)行文件、目標文件和共享庫)的各種信息。它是GNU Binutils軟件包的一部分,廣泛用于調試、分析和逆向工程。通過 objdump,用戶可以查看文件頭、段表、符號表、反匯編代碼等詳細信息。
編譯程序,然后使用objdump -t
顯示符號表,如下:
可以看到初始化的static
變量存放在.data
中。
再來確定未初始化的static
變量存放在.bss
中。修改代碼如下:
#include<stdio.h>
static int variable_a;
int main()
{printf("variable_a: %d\n", variable_a); // 驗證未初始化的static變量會被編譯器初始化為0,全局變量也一樣
}
結果如下:
然后使用objdump
查看符號表:
可以看到未初始化的static
變量存放在.bss
中。
再來確定初始化為0的static
變量也存放在.bss
中。
修改代碼如下:
#include<stdio.h>
static int variable_a=0;
int main()
{printf("variable_a: %d\n", variable_a); // 驗證未初始化的static變量會被編譯器初始化為0
}
如下:
可以看到初始化為0的static
變量存放在.bss
中。
static變量可不可以放在.h文件中
代碼如下 :
/*=====test.h=====*/
#ifndef TEST_H_
#define TEST_H_static int variable_a = 5; // 重點關注:將static變量定義在.h中
void func();#endif
/*=====test.cpp=====*/
#include"test.h"
#include<iostream>void func()
{variable_a += 5; // // test.cpp 中的static int variable_a 加2std::cout<<"test.cpp: variable_a = " << variable_a <<std::endl;
}
/*=====main.cpp=====*/
#include<iostream>
#include"test.h"
int main()
{variable_a += 2; // main.cpp 中的static int variable_a 加2std::cout << "main.cpp: variable_a = " << variable_a << std::endl;func();
}
程序說明:將static
變量定義在test.h
中,然后在main.cpp
中包含test.h
。
運行結果:
結果說明了:main.cpp
中的variable_a
和test.h
中的variable_a
是兩個獨立的變量。因為它們都是static
變量,而static
變量有隱藏的特性,所以它們互相對對方隱藏。
static 函數(shù)
static
函數(shù)和static
全局變量一樣,都有隱藏的作用,所以允許同名函數(shù)。代碼如下:
/*=====test.h=====*/
#ifndef TEST_H_
#define TEST_H_static void print();
void use_print();#endif
/*=====test.cpp=====*/
#include"test.h"
#include<iostream>void print()
{std::cout<<"hello static, test.cpp"<<std::endl;
}void use_print()
{print();
}
/*=====main.cpp=====*/
#include<iostream>
#include"test.h"void print()
{std::cout<<"hello static, main.cpp"<<std::endl;
}int main()
{print();use_print();
}
程序說明:在test.cpp
中定義了一個static
函數(shù)print()
,同時在main.cpp
中定義了一個同名函數(shù)print()
。按照我們的分析,static
函數(shù)只在test.cpp
中可見,所以使用main.cpp
包含test.h
后,main.cpp
是看不見test.h
中的print()
函數(shù)的。可以編譯運行,結果如下 :
static局部變量
?static
修飾局部變量時,使得該變量不會因為函數(shù)運行結束而丟失,使其生命周期為整個源程序。把局部變量改變?yōu)殪o態(tài)變量后是改變了它的存儲方式即改變了它的生存期。把全局變量改變?yōu)殪o態(tài)變量后是改變了它的作用域, 限制了它的使用范圍。因此static 這個說明符在不同的地方所起的作用是不同的。
代碼如下:
/*==========main.cpp==========*/
#include<iostream>int fun()
{static int variable_a = 10; // //在第一次進入這個函數(shù)的時候,variable_a被初始化為10。接著每次調用fun(),variable自加1;在static發(fā)明前,要達到同樣的功能,則只能使用全局變量: variable_a++;return variable_a;
}int main()
{for(int i=0; i<10; i++){std::cout <<"variable_a: " << fun() << std::endl;}
}
結果:
static 成員變量
代碼如下:
/*==========main.cpp===========*/
#include<iostream>class Base{
public:Base() = default;virtual ~Base() = default;
public:static int variable; /* 類內定義 */
};int Base::variable = 10; /* 類外初始化 */int main()
{std::cout<<"Base::variable = "<<Base::variable<<std::endl;
}
這段代碼肯定是可以編譯運行的,在這里我們要思考的問題是:為什么類的靜態(tài)成員變量要類內定義,類外初始化?
有一個理論答案:**因為靜態(tài)成員屬于整個類,而不屬于某個對象,如果在類內初始化,會導致每個對象都包含該靜態(tài)成員,這是矛盾的。**如果你在類內初始化,編譯會報錯,信息如下:
這里埋個坑,可不可以從代碼層面分析為什么不能這么做?
static 成員函數(shù)
**static
成員函數(shù)和static
成員變量屬于類,不屬于類的某個對象。**所以static
成員函數(shù)只能調用static
成員函數(shù)和static
成員變量。
代碼如下:
/*=========main.cpp============*/
#include<iostream>class Base{
public:Base() = default;virtual ~Base() = default;
public:static int variable_a; /* 類內定義 */int a; /* 普通成員變量 */void func1(){std::cout<<"this func1 is a member function"<<std::endl;}static void func(){ a = 4; // error: invalid use of member 'Base::a' in static member functionfunc1(); // error: cannot call member function 'void Base::func1()' without objectstd::cout<<"variable_a: " << variable_a <<std::endl;}
};int Base::variable_a = 10; /* 類外初始化 */int main()
{Base base;base.func();Base::func();
}
程序說明:在static
成員函數(shù)中調用普通成員函數(shù)和普通成員變量。
結果:程序編譯出錯,如下:
類的靜態(tài)成員函數(shù)是屬于整個類而非類的對象,所以它沒有this指針,這就導致它僅能訪問類的靜態(tài)數(shù)據(jù)和靜態(tài)成員函數(shù)。
總結
關于static
關鍵字暫時總結這么多,當然關于static
還有更多的問題,接下來遇到再更新。
參考鏈接
- https://blog.csdn.net/u011718663/article/details/118218407
- https://www.cnblogs.com/honernan/p/14478366.html