欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++的關鍵字之static你了解嗎

 更新時間:2022年02月25日 17:18:23   作者:小菜雞加油  
這篇文章主要為大家詳細介紹了C/C++的關鍵字之static,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

C語言

隱藏

場景演示

當我們同時編譯多個文件時,所有未加static前綴的全局變量和函數都具有全局可見性。會導致符號表認為存在同名全局變量和函數發(fā)生碰撞。

場景:全局的變量/函數在.h中會在多個.cc文件中擁有且全局可見有鏈接問題。

image-20220221183611526

a.h

#pragma once
#include<stdio.h>
void Test()
{
  printf("I am test..\n");
}

b.c

#include"a.h"
void call()
{
    Test();
}

c.c

#include"a.h"
int main()
{
   Test();   
}

makefile

all:c
c:c.o b.o
	gcc -o $@ $^ 
c.o:c.c
	gcc -c $^ 
b.o:b.c
	gcc -c $^ 
.PHONY:clean
clean:
	rm -rf *.o c

運行結果

image-20220221183828906

此時查看b.oc.o符號表。(readelf -s xxx.o)

image-20220221183926498

image-20220221183944564

可以看到雙方的.o符號表中都認為有一個GLOBAL全局函數的Test,兩者匯編階段形成的符號表此時在匯總的階段就會產生同名全局函數沖突。

此時在兩者的二進制文件里都認為各自擁有Test()函數,且都在全局。而全局函數只能有一個名字(注:重載是底層重新命名了)。雖然我們知道兩個Test()是同一個,但是link的時候認為有兩個同名函數實現,因此報link錯。

image-20220221184323225

解決方法

聲明和定義分離

養(yǎng)成聲明和定義分離的習慣,在.h中只聲明不定義。在.c文件中定義。

image-20220221184956320

a.h

#include<stdio.h>
void Test();

a.c

#include"a.h"
void Test()
{
    cout<<"I am test..."<<endl;
}

makefile

all:c
c:c.o b.o a.o
	gcc -o $@ $^ 
c.o:c.c
	gcc -c $^ 
b.o:b.c
	gcc -c $^ 
a.o:a.c
	gcc -c $^ 
.PHONY:clean
clean:
	rm -rf *.o c

image-20220221185142988

為什么此時就可以正常運行了?

依然查看符號表,可以發(fā)現b.o和c.o中此時只是給Test聲明留了一個全局的NOTYPE位置。

image-20220221185244568

而在a.o中定義Test(),因此a.o中是func類型。

image-20220221185352451

最后三個.o文件鏈接的時候確定Test()實際在最后生成的.out文件中的虛擬內存地址。運行時加載到內存中,之后的詳細過程就是linux創(chuàng)建進程中的事情。

image-20220221185617070

使用static關鍵字及缺陷

那如果我就是想要直接在.h中存放一個公共的全局的對象來供其他所有文件使用呢?使用static關鍵字。

a.h

#pragma once
#include<stdio.h>
static void Test()
{
  printf("I am test..\n");
}

代碼結構

image-20220221185854507

此時為什么又成立呢?兩者.o文件中為什么對同名的全局函數包容了呢?可以看到此時兩者的符號表中仍然是func,按照場景演示中的例子,應該報錯的。

image-20220221185942306

此時反匯編查看Test()函數地址。我們發(fā)現此時生成了兩個test函數,不過函數地址不同。

結論:static函數作用域僅在自己所在文件,其實是編譯后不同文件下的同名static函數會有不同的內部命名

不同.c文件include了static變量之后該變量只在各自包含該變量的.c中可見。

image-20220221190131277

既然生成了兩份,我們就可以發(fā)現,如果是一個靜態(tài)的全局變量,我們分別進行修改實際上對兩個不同的變量進行修改的。如果要解決全局變量統(tǒng)一性訪問,保證全局變量不可變即可。另外一種方式就是使用單例模式。

a.h

#pragma once
#include<stdio.h>
static int a =0;

b.h

#include"a.h"
void call();

b.c

#include"b.h"
void call()
{
   a = 1;
   printf("a=%d\n",a);
}

c.c

#include"b.h"
int main()
{
   a=2;
   printf("a=%d\n",a); 
   call();
   printf("a=%d\n",a);
}

image-20220221195458359

保持變量內容的持久

  • 全局靜態(tài)變量

在全局變量前加上關鍵字static,全局變量就定義成一個全局靜態(tài)變量。

內存中位置:靜態(tài)存儲區(qū),在整個程序運行期間移植存在。

初始化:未經初始化的全局靜態(tài)變量會被自動初始化為0(自動對象的值是任意的,除非他是被顯示初始化)。

作用域:全局靜態(tài)變量是從定義指出開始,到文件結尾,在聲明他的文件之外是不可見的。

  • 局部靜態(tài)變量

內存位置:靜態(tài)存儲區(qū)

初始化:未經初始化的局部靜態(tài)變量會被自動初始化為0(自動對象的值是任意的,除非他是被顯示初始化)。

作用域:為局部作用域,當定義他的函數或者語句塊結束時,作用域結束。但是當局部靜態(tài)變量離開作用域后,并沒有被銷毀,依然駐留在內存中,只不過我們不能再對它進行訪問,直到該函數再次被調用,并且值不變。

如下的count變量作用域在test函數中,而生命周期是整個程序。在第一次進入test()的時候會初始化,之后進入test()就不再執(zhí)行第5行代碼了。

#include<stdio.h>
void test()
{
    static int count =0;
    count++;
}
int main()
{
    for(int i =0 ; i < 10 ; i++ ) test();
}

默認初始化為0

默認初始化為0:在靜態(tài)存儲區(qū),內存中所有的字節(jié)默認值都是0x00。

#include <stdio.h>
int a;
int main(void)
{
    int i;
    static char str[10];
    printf("integer: %d;  string: (begin)%s(end)", a, str);
    return 0;
}

Cpp

static類成員變量

聲明為static的類成員稱為類的靜態(tài)成員,用static修飾的成員變量,稱之為靜態(tài)成員變量;靜態(tài)的成員變量一定要在類外進行初始化。

  • 靜態(tài)變量屬于整個類,所有對象,生命周期在整個程序間運行
  • 在類成員函數中,可以隨便訪問

static類成員方法

用static修飾的成員函數,稱之為靜態(tài)成員函數。(因為該成員變量沒有this指針)

static成員函數,沒有this指針,不使用對象就可以調用–>fun::。

靜態(tài)成員函數可以調用非靜態(tài)成員函數(/成員)嗎?不行。沒有this指針

非靜態(tài)成員函數可以調用類的靜態(tài)成員函數嗎?可以

class Date
{
    public:
    	Date(int year=0,int month=1,int day=1)
        {
        }
    	void f1()
        {
        }
    	static void f2()
        {
		   f1();//沒有this指針
        }
    private:
}
class Date{
public:
    	void f3()
        {
            f4();//突破類域+訪問限定符就可以訪問 Date::f4();/對象.f4()
            //類里面是一個整體都在類域中,類里面不受訪問限定符限制
        }
    	static void f4()
        {
        }
private:
};

單例模式

  • 單例模式

一個類只能創(chuàng)建一個對象,即單例模式,該模式可以保證系統(tǒng)中該類只有一個實例,并提供一個訪問它的全局訪問點,該實例被所有程序模塊共享。比如在某個服務器程序中,該服務器的配置信息存放在一個文件中,這些配置數據由一個單例對象統(tǒng)一讀取,然后服務進程中的其他對象再通過這個單例對象獲取這些配置信息,這種方式簡化了在復雜環(huán)境下的配置管理。

1.如何保證全局(一個進程中)只有一個唯一的實例對象

參考只能在堆上創(chuàng)建對象和在棧上創(chuàng)建對象,禁止構造和拷貝構造及賦值。

提供一個GetInstance獲取單例對象。

2.如何提供只有一個實例呢?

餓漢模式和懶漢模式。

3.使用場景

由于全局的變量在.h中會在多個.cc文件中擁有且可見容易有鏈接問題。而static又只能在當前文件可見。因此真要處理成全局的就使用單例模式。

具體的單例模式在特殊類設計中提及。

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!   

相關文章

  • 解析C++中派生的概念以及派生類成員的訪問屬性

    解析C++中派生的概念以及派生類成員的訪問屬性

    這篇文章主要介紹了解析C++中派生的概念以及派生類成員的訪問屬性,是C++入門學習中的基礎知識,需要的朋友可以參考下
    2015-09-09
  • C語言實現輸入ascii碼,輸出對應的字符方式

    C語言實現輸入ascii碼,輸出對應的字符方式

    這篇文章主要介紹了C語言實現輸入ascii碼,輸出對應的字符方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • C++中不能被重載的運算符介紹

    C++中不能被重載的運算符介紹

    其實在C/C++ 里大多數運算符都可以在C++中被重載的。C 的運算符中只有 . 和 ?:(以及 sizeof,技術上可以看作一個運算符)不可以被重載
    2013-10-10
  • C++類的定義與實現

    C++類的定義與實現

    這篇文章主要介紹了C++類的定義與實現,違章圍繞C++類的定義的相關資料展開全文內容,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-01-01
  • C語言中的鏈接編寫教程

    C語言中的鏈接編寫教程

    這篇文章主要介紹了C語言中的鏈接編寫教程,是C語言入門學習中的基礎知識,需要的朋友可以參考下
    2015-08-08
  • C++實現LeetCode(102.二叉樹層序遍歷)

    C++實現LeetCode(102.二叉樹層序遍歷)

    這篇文章主要介紹了C++實現LeetCode(102.二叉樹層序遍歷),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-07-07
  • C/C++數據對齊詳細解析

    C/C++數據對齊詳細解析

    通常我們在寫代碼的時候是不需要考慮對齊的影響的,都是依賴編譯器來為我們選擇適合的對齊策略,我們也可以通過傳遞給編譯器預編譯指令來指定數據對齊的方法
    2013-10-10
  • 關于UDP服務器客戶端編程流程介紹

    關于UDP服務器客戶端編程流程介紹

    大家好,本篇文章主要講的是關于UDP服務器客戶端編程流程介紹,感興趣的同學趕快來看看吧,對你有幫助的話記得收藏
    2021-12-12
  • C語言實現獲取文件MD5值

    C語言實現獲取文件MD5值

    MD5(Message?Digest?Algorithm?5)是一種常用的哈希函數算法,這篇文章主要介紹了C語言如何獲取文件MD5值,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-08-08
  • C++實現俄羅斯方塊(linux版本)

    C++實現俄羅斯方塊(linux版本)

    這篇文章主要為大家詳細介紹了linux版本C++實現俄羅斯方塊,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07

最新評論