你有没有遇到叫二狗子的那个哥们?
原文 調侃C中的define,CSDN同步發布。
轉載請注明出處,謝謝!
二狗子
二狗子這個名字,在大街小巷,在電視劇中幾乎都能聽到。我也不知道老一輩的父母為什么這么喜歡給自己的孩子取這樣的名字,唯一能讓我信服的理由是:順口!大叔大伯們之所以叫這個名字還有一個理由,之前孩子多,希望孩子像小狗兒一樣好喂養。
正好我們村有個孩子也叫二狗子,大名叫張力萬,無論是叫二狗子還是叫張力萬,都指的是同一個人。我們大多數情況下還是叫他二狗子,他也習慣了倒也覺得親切,叫張力萬一般都是在正式場合。
有些企業文化中規定:“不允許在公司直接喊同事的名字,每個人必須有個英文名”。比如二狗子入職到這樣的企業,大家不允許喊他二狗子或者張力萬,于是二狗子又有了一個英文名:“Jack”,你看 “Jack” 這個名字既符合企業文化又聽起來高大尚。
無論是 “二狗子“ 還是 “Jack“ 都是張力萬的別名。
在 C 語言中,關鍵字 define 和 typedef 就可以用來取別名,但是二者又有不同點,今天主要分享一下 define 的用法。
下面是使用 define 來模擬別名,示例如下:
#define Zhangliwan1 "二狗子" #define Zhangliwan2 "Jack"#define Zhangliwan "張力萬"int main(int argc, const char *argv[]) {printf("我們村的%s可以叫他%s也可以叫他%s\n", Zhangliwan, Zhangliwan1, Zhangliwan2);return 0; }輸出結果:
我們村的張力萬可以叫他二狗子也可以叫他Jack虛構一下
丹尼斯·里奇 一個偉大而低調的牛人,是Unix之父、C語言之父。
丹尼斯·里奇還將Unix的設計原則定為 KISS 原則 即 Keep it simple stupid,保持簡單和直接,所以Unix一直都是經典中的經典。這也說明丹尼斯·里奇不僅是一個優秀的工程師,還是一個優秀的產品經理。
我在想,當初丹尼斯·里奇和肯·湯普遜在實驗室里沒事也會討論C語言的事情。
丹尼斯·里奇:“老兄,你看我們現在的語言是不是過于復雜了?”
肯·湯普遜:“的確有點復雜,我有個大膽的想法,不知當講不當講?”
丹尼斯·里奇:“你還跟我墨跡啥,有話直接說唄,呵呵!”
肯·湯普遜:“嗯,我們可以開發一門新的語言,他要足夠的簡單、高效。”
丹尼斯·里奇:“想法是挺好的,那就開干吧!”
于是C語言誕生了。
肯·湯普遜:“你有沒有覺得我們在定義常量的時候不太方便?”
丹尼斯·里奇:“是呀,這樣你看行不行,弄個預處理器可以讓我們任意定義常量,暫時稱他為 ‘宏’ 吧!”
肯·湯普遜:“我覺得完全沒有問題,來,徒手寫一個。”
丹尼斯·里奇:“哈哈,給力!”
于是 define 就有了。
以上純屬個人猜想,并不是冒犯兩位大師,本故事純屬虛構,如有雷同,純屬巧合。Unix和C語言的大道至簡,對后代科學的發展奠定了不可磨滅的貢獻和影響。
基本用法
關鍵字 define 是 C 語言中的預處理命令,它用于宏定義,在大多數定義下可以提高代碼的可讀性,為編程提供方便。
在 C 語言中預處理命令以 “#” 號開頭,如 #include、#ifdef、#endif 和宏定義命令 #define 等。
關鍵字 define 的用法如下:
#define 新類型名 原類型名 #define INTEGER int INTEGER a = 100;#define PI 3.1415927#define UserName "user_name"#define MAX(x, y) (x)>(y)?(x):(y);在 C 語言中,關鍵字 define 的定義的常量都會在預處理階段將用到的別名直接被原樣替換掉。例如在編寫源程序時,所有用到 3.1415927 的地方都可用 PI 代替,而編譯時,將先由預處理程序進行宏代換即用 3.1415927 去置換所有的宏名 PI,然后再進行編譯。
關鍵字 define 還可以結合 “#”、“##”、“#@” 使用。
- 符號 “#”,表示將其字符串化。
- 符號 “##”,表示連接變量。
- 符號 “#@”,表示將其字符化。
我使用 “#@” 定義,無論是GCC編譯器還是Clang編譯器都無法通過編譯,錯誤信息:“ ‘#’ is not followed by a macro parameter ”,但是在 Visual Studio 中編譯就沒有問題。示例如下:
#define K(x) #@x關鍵字 define 給我們寫代碼帶來了一定的便利,但是如果過多的亂用它也會代碼不小的麻煩,比如下面的例子:
#define square(x) x*xint main() {int i;i = 64/square(4);printf("i = %d\n", i);return 0; }定義宏 square(x) 本來是求某個數的平方,按理說 64/16 結果應該是 4,但是運行程序你會發現結果是 64.
我們把上面的例子展開,因為 define 是直接原樣替換,如下:
i = 64/4*4; i = 16*4; i = 64;修改一下程序中 define 的定義,結果就對了。
#define square(x) (x*x)int main() {int i;i = 64/square(4);// 4printf("i = %d\n", i);return 0; }其實最安全的做法是這樣定義,如下:
#define square(x) ({ \ typeof(x) y = (x); \ y*y; \ })作用域
可以在C文件的開頭,也可以在方法體里面,還可以在方法的聲明前都可以使用 define 關鍵字。
定義在文件開頭:
#define NAME "name"int main() {printf("Define NAME: %s\n", NAME);return 0; }定義在方法中:
void play() {#define NAME "name"printf("Define NAME: %s\n", NAME); }這里要注意,定義在方法中,并不是指該宏定義 NAME 只能用在該方法里面,其他地方照樣可以使用。
void play() {#define NAME "name"printf("Define NAME: %s\n", NAME); }/* 注意:該方法一定是在define定義之后才能使用NAME */ void eat() {printf("Define NAME: %s\n", NAME); }條件編譯
在C語言中或者在類C語言中如Objective-C和C++中,我們會經常用到條件編譯語句,如下:
#ifdef NAME#else#endif大家在做一些跨平臺開發工作的時候,也會用到條件編譯語句。
#ifdef ANDROID #define PLAYFORM 1 #else #define PLAYFORM 2 #endif還有就是類似防止重復包含(重復定義)頭文件,也會用到條件編譯,如下:
#ifndef __Header_Person_H__ #define __Header_Person_H__ #endif下面是來自Linux Kernel里面的代碼片段:
#if defined(CONFIG_ALPHA_GENERIC) #define GAMMA_BIAS alpha_mv.sys.t2.gamma_bias #elif defined(CONFIG_ALPHA_GAMMA) #define GAMMA_BIAS _GAMMA_BIAS #else #define GAMMA_BIAS 0 #endif既然我們可以定義宏,那么是否可以取消宏定義呢?答案是當然可以。
void play() {#define NAME "name"printf("Define NAME: %s\n", NAME); }#ifdef NAME // 取消宏定義 #undef NAME #endifvoid eat() {// Compile errror: Use of undeclared identifier 'NAME'printf("Define NAME: %s\n", NAME); }這份 GNU Macors 在線文檔介紹了很多關于宏定義的知識,可以點擊前往學習。
時間可以改變一切,但你得做點什么!
總結
以上是生活随笔為你收集整理的你有没有遇到叫二狗子的那个哥们?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络攻防实验之缓冲区溢出攻击
- 下一篇: 基于springboot的在线心理测评系