C++中常用關鍵字詳解(2)

2023-08-08 16:05:48 來源:Linux兵工廠

volatile

C++中,volatile是一個關鍵字,用于修飾變量,告訴編譯器該變量的值可能在程序流程之外被意外修改,因此編譯器不應該對該變量進行優化(如緩存變量值或重排指令順序)。

volatile主要用于以下場景:

1、多線程訪問共享變量:在多線程編程中,如果一個變量被多個線程訪問,并且其中一個線程可能會修改該變量的值,就應該使用volatile修飾該變量,以確保線程能夠正確讀取變量的最新值,而不是從緩存中讀取舊值。


(資料圖片)

2、中斷處理:在嵌入式系統硬件相關的編程中,中斷處理程序中通常會訪問硬件寄存器或其他與硬件相關的狀態變量。由于中斷處理程序可能在程序的正常流程之外執行,為了確保正確處理這些變量,應使用volatile修飾。

以下是一個簡單的示例,演示了volatile的用法:

#include < iostream >#include < thread >volatile int sharedVariable = 0;void modifySharedVariable() {    for(int i = 0; i < 5; ++i) {        sharedVariable = i;        std::this_thread::sleep_for(std::chrono::milliseconds(100));    }}void readSharedVariable() {    for (int i = 0; i < 5; ++i) {        std::cout < < "Read sharedVariable: " < < sharedVariable < < std::endl;        std::this_thread::sleep_for(std::chrono::milliseconds(200));    }}int main() {    std::thread writerThread(modifySharedVariable);    std::thread readerThread(readSharedVariable);    writerThread.join();    readerThread.join();    return 0;}

在上述示例中,我們使用了volatile修飾sharedVariable變量。modifySharedVariable()函數在循環中不斷修改sharedVariable的值,而readSharedVariable()函數在另一個線程中循環讀取sharedVariable的值。由于sharedVariable是一個共享變量,在多線程環境下,為了避免讀取舊值,我們使用volatile修飾,確保readSharedVariable()函數能夠正確讀取到最新的值。

需要注意的是,volatile修飾符只用于修飾變量,而不是函數。它不會解決所有多線程問題,更復雜的線程同步問題可能需要使用互斥鎖(std::mutex)或其他同步機制來保證正確性。

assert()

在C++中,assert()是一個宏定義,用于在代碼中進行斷言檢查。它是一個調試工具,用于在程序運行時檢查某個條件是否為真。如果斷言條件為假(即false),則會觸發斷言失敗,并導致程序中止執行。在發布版本中,默認情況下,斷言會被禁用,因此不會對性能產生影響。

assert()宏的定義位于頭文件中,通常在開發階段使用,以幫助開發者檢測程序中的錯誤和問題。在調試階段,當斷言條件為假時,它會輸出錯誤信息,并在終端顯示斷言失敗的位置和原因。

斷言的一般語法如下:

#include < cassert >int main() {    int x = 10;    assert(x == 5); // 斷言條件為假,程序會終止,并顯示錯誤信息    return 0;}

在上述代碼中,assert(x == 5)會檢查變量x是否等于5。由于x的值為10,斷言條件為假,程序會終止執行,并顯示斷言失敗的信息,如文件名、行號、條件表達式等。

需要注意的是,由于在發布版本中默認會禁用斷言,因此不應該將assert()用于對用戶輸入進行驗證或執行關鍵業務邏輯。對于這些情況,應該使用更穩健的錯誤處理機制。

在開發過程中,合理使用assert()可以幫助發現代碼中的問題,提高程序的健壯性和可維護性。但在最終發布版本中,需要確保去除所有不必要的斷言,以確保代碼的性能和正確性。

sizeof()

在C++中,sizeof是一個運算符,用于計算類型或變量的大小(字節數)。它的語法形式為sizeof (type)sizeof expression

運算符有以下幾個特點和使用場景:

返回值:sizeof運算符返回一個size_t類型的值,表示類型或變量所占用的字節數。對類型的大小計算:對于給定的數據類型,sizeof(type)可以計算出該類型的大小。例如:
#include < iostream >int main() {    std::cout < < "Size of int: " < < sizeof(int) < < " bytes" < < std::endl;    std::cout < < "Size of double: " < < sizeof(double) < < " bytes" < < std::endl;    return 0;}

輸出可能為:

Size of int: 4 bytesSize of double: 8 bytes
對變量的大小計算:sizeof運算符也可以計算變量所占用的字節數。例如:
#include < iostream >int main() {    int x = 10;    double y = 3.14;    std::cout < < "Size of x: " < < sizeof(x) < < " bytes" < < std::endl;    std::cout < < "Size of y: " < < sizeof(y) < < " bytes" < < std::endl;    return 0;}

輸出可能為:

Size of x: 4 bytesSize of y: 8 bytes
對數組的大小計算:對于數組,sizeof運算符可以計算整個數組所占用的總字節數。例如:
#include < iostream >int main() {    int arr[] = {1, 2, 3, 4, 5};    std::cout < < "Size of arr: " < < sizeof(arr) < < " bytes" < < std::endl;    return 0;}

輸出可能為:

Size of arr: 20 bytes
對指針的大小計算:sizeof運算符計算指針變量本身的大小,而不是指針所指向的對象的大小。無論指針指向的對象類型大小是多少,指針本身的大小都是固定的。
#include < iostream >int main() {    int x = 10;    int* ptr = &x;    std::cout < < "Size of ptr: " < < sizeof(ptr) < < " bytes" < < std::endl;    return 0;}

輸出可能為:

Size of ptr: 8 bytes (在 64 位系統上)

請注意,sizeof運算符在編譯時計算,不會真正運行代碼。因此,它在編譯時就能知道類型或變量的大小,并返回一個常量值。

總之,sizeof運算符是一個非常有用的工具,用于在編程中確定數據類型和變量的大小,特別是在處理內存分配、結構體、數組等場景中。

#pragma pack(n)

在C++中,#pragma pack(n)是一個預處理指令(preprocessor directive),用于告訴編譯器按照指定的字節對齊方式對結構體或類進行內存對齊。通常情況下,編譯器會對結構體或類進行自動的內存對齊,以提高訪問效率和性能。

#pragma pack(n)的語法中,n是指定的對齊字節數,可以是1、2、4、8等,表示結構體或類的成員變量將按照n字節對齊。在結構體或類定義之前使用該預處理指令,其作用會影響接下來的結構體或類的成員排列。

以下是一個簡單的示例,演示了#pragma pack(n)的用法:

#include < iostream >// 默認情況下,編譯器會進行自動對齊,對于int類型通常是4字節對齊struct MyStructAuto {    char c;    int i;};// 使用 #pragma pack(1) 指定1字節對齊,取消自動對齊#pragma pack(1)struct MyStructPacked {    char c;    int i;};#pragma pack()int main() {    std::cout < < "sizeof(MyStructAuto): " < < sizeof(MyStructAuto) < < std::endl;    std::cout < < "sizeof(MyStructPacked): " < < sizeof(MyStructPacked) < < std::endl;    return 0;}

輸出可能為:

sizeof(MyStructAuto): 8sizeof(MyStructPacked): 5

在上述示例中,我們定義了兩個結構體:MyStructAutoMyStructPacked。在MyStructAuto中,編譯器會自動進行對齊,默認情況下,int類型通常是4字節對齊,因此MyStructAuto的大小是8字節(1字節的char加上4字節的int,再加上3字節的填充)。

而在MyStructPacked中,我們使用了#pragma pack(1)指定了1字節對齊,這將取消自動對齊,導致MyStructPacked的大小只有5字節(1字節的char加上4字節的int,沒有填充字節)。

需要注意的是,使用#pragma pack(n)可能會影響內存對齊,導致結構體或類的訪問效率降低,尤其是對于大型結構體。在使用#pragma pack(n)時,應謹慎考慮,確保了解其影響,并只在必要時使用。通常情況下,讓編譯器自動進行內存對齊是較為推薦的做法。

標簽:

上一篇:C++中常用關鍵字詳解(3)
下一篇:最后一頁