C語言語法_C語言中(void)(&_a == &_b)或者更為抽象的(void)object的作用
非技術性文章,只是為了分享解決問題的方法
小白在複習C語言資料結構檢視Linux原始碼的時候,看到了Linux原始碼中MAX(a,b)的實現,它能夠比較2個任意型別的資料(可行的情況下)並獲得最大值,實現得非常通用。Linux是利用巨集,並且使用了GNU的擴充套件語法:typeof()和語句表示式實現的,程式碼如下:
#define MAX(a,b) \
({\
typeof(a) _a = a;\
typeof(b) _b = b;\
(void)(&_a == &_b);\
((_a)>(_b)?(_a):(_b));\
})
擴充套件語法:
typeof()
出現在3行,很好理解,typeof(a)就是獲得變數a的型別,這樣做的目的有2個,①實現任意型別的比較,使得使用者的可選擇性更大,對資料型別的包容性更高。②是為了使得巨集引數在巨集定義中只出現一次,避免在使用MAX()的時候巨集引數出現二義性,比如MAX(a++,b)如果沒有3-4行,巨集展開的時候,a++會出現在多個地方,結果會出人意料,有疑惑的可以上機實現。
( { } )
這個東東出現在2行-7行,比較難以接受,它是GNU的擴充套件語法,叫做語句表示式,內層的{ }表示一個複合語句,外層的括號()目的是為了符合C語言中“複合語句不能出現在表示式中”的語法規定,既然{ }是複合語句,那麼再加一層括號()使得其變為表示式,沒錯,就是這麼拗口。一般用法為var = ( { others;(val) ;} ),其中的others;就是一系列的完整語句,(val)是必須的,它作為語句表示式最後的值,因為C語句規定每一個表示式到最後都必須有一個值,對應著上面程式碼6行帶三目運算子的表示式 ,也就是實際求出最大值的表示式。
現在有一個相當令人費解的語句,它就是5行的:(void)(&_a == &_b);
在解決這個語句之前,小白突然想起自己學ZigBee協議棧的時候,也出現了類似的語句,查詢ZigBee協議棧的實現,發現瞭如下程式碼:
uint16 HalUARTWrite(uint8 port, uint8 *buf, uint16 len)
{
(void)port;
(void)buf;
(void)len;
#if (HAL_UART_DMA == 1)
if (port == HAL_UART_PORT_0) return HalUARTWriteDMA( buf, len);
……
}
這是hal_uart.c函式,其中出現了(void)xxx的語句,相當疑惑,最後發現其作用:佔位!!
(void)object的作用:消除編譯器對object沒有引用的警告
由於ZigBee協議棧只是提供了基本的網路通訊和底層初始化實現,當自己需要特定功能的時候,往往要修改某些函式,而這些函式的函式簽名是不能改變的,其中之一就是引數列表是不能修改的,而有時候自己的函式並不需要用到某些引數,那麼這些引數在函式中就相當於沒有被引用,根據C語音的語法檢查,當一個變數沒有被引用的時候,編譯器會給出警告,作為例子而言,在Qt下的一個C程式:
int main(int argc, char *argv[])
{
int ago = 100;
int min = -1;
printf("%d",ago); //只引用ago,沒有引用argc\argv\min
return 0;
}
由於main引數argc和argc以及變數min都沒有被引用,因此編譯器出現以下警告:
而ZigBee函式非常多,如果自己修改的函式通通給出警告,那麼編譯的時候是非常令人煩惱的,程式沒有出錯但是警告一大堆,為了遮蔽這些警告,需要對這些可能沒有引用的變數佔位,佔位也就是無意義地去引用變數,(void)port就是把port變數型別強制轉換為void但是沒有下一步操作,這個語句對變數引用是無意義的,但是確實引用了變數,編譯器就不會給出警告。
我們修改一下程式:
int main(int argc, char *argv[])
{
int ago = 100;
int min = -1;
(void)argc;
(void)argv;
(void)min;
printf("%d",ago);
return 0;
}
再次執行程式,無任何警告:
至於有人問為什麼是(void),而不是(int)/(char)等等?答案是,無關緊要,只要你願意,完全可以用任何型別,但是由於大家都直接用(void),因此(void)也變成了不成文的規定,就像標頭檔案中防止多重包含的 #ifndef _NAME_H_等,為什麼基本都是這種寫法,其它寫法不可以嗎??當然可以,只是大家都這樣做,成為了不成文規定,你也應該跟著這樣做,否則別人閱讀你的程式碼時會顯得很疑惑。
Linux的(void)(&_a == &_b)作用:消除編譯器&_a == &_b沒有被引用的警告,同時可能得到型別不一致的警告
言歸正傳,仔細觀察這個語句:(void)(&_a == &_b); ,它的取出_a和_b的地址進行比較,然後得到一個bool值,接著進行強制型別轉換這一個無意義的變數引用操作。
這裡的目的是為了給出有用的警告,因為Linux核心的這個MAX函式是實現2個任意型別的資料比較並獲得最大值,當實際的兩個資料型別不一樣的時候,或許它們之間確實能夠比較,就像100和12.2,但是為了提醒使用者它們型別不一樣,需要把兩個資料的地址進行比較(&_a == &_b),不過單純的地址比較對編譯器而言並沒有意義,編譯器會覺得這是一個沒有引用的內容,會給出額外的警告,而Linux只是想給出型別不一致的警告,並不想要其它警告,所以在地址比較後進行強制型別轉換,消除了沒有被引用的警告,得到可能型別不一致的警告。
相關推薦
C語言語法_C語言中(void)(&_a == &_b)或者更為抽象的(void)object的作用
非技術性文章,只是為了分享解決問題的方法 小白在複習C語言資料結構檢視Linux原始碼的時候,看到了Linux原始碼中MAX(a,b)的實現,它能夠比較2個任意型別的資料(可行的情況下)並獲得最大值,實現得非常通用。Linux是利用巨集,並且使用了GNU的
深入C++中API的問題詳解_C 語言
前言:本文書寫的格式與其它不相同。本文題目說是關於C++ API的思考,其實也不僅僅是C++,對於其它語言同樣適用。 API實際是指Application Programming Interface,應用程式程式設計介面。對API是一套用來控制Windows的各個部件的外觀和行為的一套預先定義的Window
第01節:Linux 內核中的 C 語言語法擴展
個數 目前 standard 目標 修飾符 協議 n) gen inux 1.1 Linux 內核驅動中的奇怪語法 大家在看一些 GNU 開源軟件,或者閱讀 Linux 內核、驅動源碼時會發現,在 Linux 內核源碼中,有大量的 C 程序看起來“怪怪的”。說它是C語言吧,
C語言文件路徑中的”/“和““
inux 規則 ref html 必須 問題 follow 字符 bat文件 在不同系統的情況系 windows下是\,linux和unix下是/ 但在win中沒有本質區別。 但是由於 \ 也是轉義字符的起始字符, 所以, 路徑中的 \ 通常需要
C語言頭文件中定義全局變量導致重復定義錯誤
語言 總結 多個 sof pan 全局變量 現在 程序編譯 升級 合作方升級SDK後,程序編譯出現變量重復定義的錯誤,通過錯誤提示無法找到什麽位置重復定義了,但確定是引入新SDK後才出現的錯誤,從SDK的頭文件中查找,最終發現在頭文件中定義了全局變量 我們的項目在多個頭文件
帶你一起學習C語言語法
作用域 鏈接 指向 nbsp itl switch語句 一個 字符串 單鏈表 《帶你學C帶你飛》第一季講解內容:C語言語法,我們會講變量、數組、函數、指針、結構、標準庫這樣一些純粹的C語言知識。 基本上你大學第一學期學的就是咱第一季的內容,我知道很多朋友學完C語言一時感覺沒
C語言語法匯總
很大的 高效 並不會 開始 現在 會有 入門學習 並不是 古人 從初學C語言到現在已經四年了,一直沒有找到空閑的時間來將自己學到的知識進行一次高效的匯總,古人又雲:學而不思則罔。近日忙裏偷閑,將自己四年來所學所思關於C語言基礎部分的學習進行一次高效的匯總,以便未來回憶起
教科書不應該再過多介紹的C語言語法
屏幕 檢查 展示 個數 鍵盤 上下 作用域 除法 vol C語言也許挺簡單,但是C標準有700頁,所以,如果你不想花費畢生精力去研究它,那麽你應該知道哪些部分可以被忽略。讓我們從二合字母或者三合字母開始,如果你的鍵盤缺少{}鍵,你可以用<%和%>來替代,就像是i
c語言語法目錄一
區分大小寫 計算器 無符號 使用 64位 AI 構架 include blog 1、#include<stdio.h> include 是要告訴編譯器,包含一個頭文件 在c語言中,任何庫函數調用都需要提前包含頭文件 <頭文件> 代表讓c
C語言語法目錄二
常量 efault spa gist getchar() 語言 sig 需要 -s 1、char類型 char c;定義了一個char變量 ‘a‘ ; char常量 char的本質就是一個整數,一個只有一個字節大小的整數 char c; 定義一個有符號的c
『Python CoolBook』C擴展庫_其五_C語言層面Python庫之間調用API(待續)
新的 c庫 ati .com 創建 結構 指針 內存 point 一、C層面模塊添加API 我們仍然操作如下結構體, #include <math.h> typedef struct Point { double x,y; } Po
C語言編譯數組中有的加code有的不加,有什麽區別
hid 比較 嵌入 編碼 系統 itl targe www bsp 像uchar code table[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};和uchar ds1302[]={0xfe,0xfd,0xfb,0xf7,0
C語言語法教程-結構體
再次 staf har 語言 指向 取出 但是 進行 字符數 2018-09-30 結構體中成員變量地址是連續的,結構體用於描述記錄。 Create a struct //---------------------------- //struct1.c //創建一個結構體,
C語言--查詢數組中出現次數最多的元素
次數 最大值 定義 style 取出 ++ main print 存儲 查詢數組中出現次數最多的元素#include <stdio.h> #include <malloc.h> #include <stdlib.h> int max_c
C語言解決螺旋矩陣演算法問題的程式碼示例_C 語言
趕集網校招就採用了螺旋輸出矩陣作為程式題,要求將矩陣螺旋輸出如: 2016425180442470.jpg 圖中6*6矩陣線條所示為輸出順序,如果輸出正確的話應該輸出1~36有序數字。我想的是這麼做的: #include <stdio.h> //#define LEN 1 //#define
C語言:一個數組中只有兩個數字是出現一次
1 //1.一個數組中只有兩個數字是出現一次, 2 //其他所有數字都出現了兩次。 3 //找出這兩個數字,程式設計實現。a 4 5 //^=單獨兩個數的^結果 6 //單獨出現的兩個數不同位的標記 7 //position: ^結果中第一個出現1的位置 8 //position位
5.1-day01-C++語言語法基礎
bank.cpp #include <iostream> using namespace std; //namespace { void print (int money) { cout << money <&
1.1-day01-C++語言語法基礎
C++語言語法基礎 一、C++語言語法基礎(6) 1.從C到C++的過渡(1) 2.類和物件(2) 3.操作符過載(1) 4.繼承與多型(1)
【C語言中的細節問題】C/C++浮點數在記憶體中的儲存方式
C/C++浮點數在記憶體中的儲存方式 本文轉載自:https://www.cnblogs.com/dolphin0520/archive/2011/10/02/2198280.html 任何資料在記憶體中都是以二進位制
C語言找出字串中的特定的字元,並輸出
這裡我們用到了函式 strchr 這個函式返回值是一個指標 函式引數是 一個字串和一個字元。 #include <stdio.h> #include<string.h> void main() { char str[80]; char c