C 和 Object- C 中得 #ifdef 和#ifndef

很多宏是為了進行條件編譯。一般情況下,源程序中所有的行都參加編譯。但是有時希望對其中一部分內容只在滿足一定條件才進行編譯,也就是對一部分內容指定編譯的條件,這就是“條件編譯”。有時,希望當滿足某條件時對一組語句進行編譯,而當條件不滿足時則編譯另一組語句。?
??? 條件編譯命令最常見的形式為:?
??? #ifdef 標識符?
??? 程序段1?
??? #else?
??? 程序段2?
??? #endif?
?????
??? 它的作用是:當標識符已經被定義過(一般是用#define命令定義),則對程序段1進行編譯,否則編譯程序段2。?
??? 其中#else部分也可以沒有,即:?
??? #ifdef?
??? 程序段1?
??? #denif?
?????
??? 這里的“程序段”可以是語句組,也可以是命令行。這種條件編譯可以提高C源程序的通用性。如果一個C源程序在不同計算機系統上系統上運行,而不同的計算機 又有一定的差異。例如,我們有一個數據類型,在Windows平臺中,應該使用long類型表示,而在其他平臺應該使用float表示,這樣往往需要對源 程序作必要的修改,這就降低了程序的通用性。可以用以下的條件編譯:?
??? #ifdef WINDOWS?
??? #define MYTYPE long?
??? #else?
??? #define MYTYPE float?
??? #endif?
?????
??? 如果在Windows上編譯程序,則可以在程序的開始加上?
??? #define WINDOWS?
?????
??? 這樣則編譯下面的命令行:?
??? #define MYTYPE long?
?????
??? 如果在這組條件編譯命令之前曾出現以下命令行:?
??? #define WINDOWS 0?
?????
??? 則預編譯后程序中的MYTYPE都用float代替。這樣,源程序可以不必作任何修改就可以用于不同類型的計算機系統。當然以上介紹的只是一種簡單的情況,可以根據此思路設計出其它的條件編譯。?
??? 例如,在調試程序時,常常希望輸出一些所需的信息,而在調試完成后不再輸出這些信息。可以在源程序中插入以下的條件編譯段:?
??? #ifdef DEBUG?
??? print ("device_open(%p)\n", file);?
??? #endif?
?????
??? 如果在它的前面有以下命令行:?
??? #define DEBUG?
?????
??? 則在程序運行時輸出file指針的值,以便調試分析。調試完成后只需將這個define命令行刪除即可。有人可能覺得不用條件編譯也可達此目的,即在調試 時加一批printf語句,調試后一一將printf語句刪除去。的確,這是可以的。但是,當調試時加的printf語句比較多時,修改的工作量是很大 的。用條件編譯,則不必一一刪改printf語句,只需刪除前面的一條“#define DEBUG”命令即可,這時所有的用DEBUG作標識符的條件編譯段都使其中的printf語句不起作用,即起統一控制的作用,如同一個“開關”一樣。?
??? 有時也采用下面的形式:?
??? #ifndef 標識符?
??? 程序段1?
??? #else?
??? 程序段2?
??? #endif?
?????
??? 只是第一行與第一種形式不同:將“ifdef”改為“ifndef”。它的作用是:若標識符未被定義則編譯程序段1,否則編譯程序段2。這種形式與第一種形式的作用相反。?
??? 以上兩種形式用法差不多,根據需要任選一種,視方便而定。?
??? 還有一種形式,就是#if后面的是一個表達式,而不是一個簡單的標識符:?
??? #if 表達式?
??? 程序段1?
??? #else?
??? 程序段2?
??? #endif?
?????
??? 它的作用是:當指定的表達式值為真(非零)時就編譯程序段1,否則編譯程序段2。可以事先給定一定條件,使程序在不同的條件下執行不同的功能。?
??? 例如:輸入一行字母字符,根據需要設置條件編譯,使之能將字母全改為大寫輸出,或全改為小寫字母輸出。?
??? #define LETTER 1?
??? main()?
??? {?
??? char str[20]="C Language",c;?
??? int i="0";?
??? while((c=str[i])!='\0'){?
??? i++;?
??? #if LETTER?
??? if(c>='a'&&c<='z') c="c-32";?
??? #else?
??? if(c>='A'&&c<='Z') c="c"+32;?
??? #endif?
??? printf("%c",c);?
??? }?
??? }?
?????
??? 運行結果為:C LANGUAGE?
??? 現在先定義LETTER為1,這樣在預處理條件編譯命令時,由于LETTER為真(非零),則對第一個if語句進行編譯,運行時使小寫字母變大寫。如果將程序第一行改為:?
??? #define LETTER 0?
?????
??? 則在預處理時,對第二個if語句進行編譯處理,使大寫字母變成小寫字母(大寫字母與相應的小寫字母的ASCII代碼差32)。此時運行情況為:?
??? c language?
??? 有人會問:不用條件編譯命令而直接用if語句也能達到要求,用條件編譯命令有什么好處呢?的確,此問題完全可以不用條件編譯處理,但那樣做目標程序長(因 為所有語句都編譯),而采用條件編譯,可以減少被編譯的語句,從而減少目標的長度。當條件編譯段比較多時,目標程序長度可以大大減少。

# ifdef? #ifndef 等用法

????? 頭件的中的#ifndef,這是一個很關鍵的東西。比如你有兩個C文件,這兩個C文件都include了同一個頭文件。而編譯時,這兩個C文件要一同編譯成一個可運行文件,于是問題來了,大量的聲明沖突。

還是把頭文件的內容都放在#ifndef和#endif中吧。不管你的頭文件會不會被多個文件引用,你都要加上這個。一般格式是這樣的:

#ifndef <標識>?
#define <標識>

......?
......

#endif

<標識>在理論上來說可以是自由命名的,但每個頭文件的這個“標識”都應該是唯一的。標識的命名規則一般是頭文件名全大寫,前后加下劃線,并把文件名中的“.”也變成下劃線,如:stdio.h

#ifndef _STDIO_H_?
#define _STDIO_H_

......

#endif

2.在#ifndef中定義變量出現的問題(一般不定義在#ifndef中)。

#ifndef AAA
#define AAA
...
int i;
...
#endif
里面有一個變量定義
在vc中鏈接時就出現了i重復定義的錯誤,而在c中成功編譯。

結論:

(1).當你第一個使用這個頭的.cpp文件生成.obj的時候,int i 在里面定義了當另外一個使用這個的.cpp再次[單獨]生成.obj的時候,int i 又被定義然后兩個obj被另外一個.cpp也include 這個頭的,連接在一起,就會出現重復定義.

(2).把源程序文件擴展名改成.c后,VC按照C語言的語法對源程序進行編譯,而不是C++。在C語言中,若是遇到多個int i,則自動認為其中一個是定義,其他的是聲明。

(3).C語言和C++語言連接結果不同,可能(猜測)時在進行編譯的時候,C++語言將全局
變量默認為強符號,所以連接出錯。C語言則依照是否初始化進行強弱的判斷的。(參考)

解決方法:

(1).把源程序文件擴展名改成.c。

(2).推薦解決方案:
.h中只聲明 extern int i;在.cpp中定義


#ifndef __X_H__
#define __X_H__
extern int i;
#endif //__X_H__

int i;

注意問題:

(1).變量一般不要定義在.h文件中。

轉載于:https://www.cnblogs.com/mcj-coding/p/3615682.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376052.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376052.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376052.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言基礎小齋

一、C語言數據類型 ok&#xff0c;如我們所知&#xff0c;C語言作為大學工科專業的必學課程&#xff0c;其重要性不言而喻&#xff1b;它為我們提供了豐富的數據類型&#xff0c;所以它很適合程序員來編寫 數據庫 &#xff0c;如DB2、Oracale都是C語言編寫的。 那么C語言具體又…

《Cracking the Coding Interview》——第11章:排序和搜索——題目8

2014-03-21 22:23 題目&#xff1a;假設你一開始有一個空數組&#xff0c;你在讀入一些整數并將其插入到數組中&#xff0c;保證插入之后數組一直按升序排列。在讀入的過程中&#xff0c;你還可以進行一種操作&#xff1a;查詢某個值val是否存在于數組中&#xff0c;并給出這個…

gradle打包java項目_gradle打包java項目

轉載地址&#xff1a;http://www.gfzj.us/series/gradle/2014/12/12/gradle%E5%B0%8F%E7%B3%BB%E5%88%97(4)--gradle%E6%89%93%E5%8C%85java%E9%A1%B9%E7%9B%AE.html以gradle小系列所舉例子為示例&#xff0c;在此處介紹兩種gradle發布java項目的方法&#xff1a;fat jar方式該…

堡壘機2.0

一、編輯系統環境變量&#xff0c;讓用戶登錄后自動調用腳本 1 vim /etc/profile 2 python /baolei/ssh_login.py 3 # 判斷登錄用戶是否為 root 用戶&#xff0c;root用戶退出程序不進行logout操作&#xff0c;否則則logout 4 if [ $? ! 10 ];then 5 echo "Good …

Flex中利用ByteArray與BitmapData互相轉換實現圖片的二進制保存與復原

Flex中利用ByteArray與BitmapData互相轉換實現圖片的二進制保存與復原 近 日在項目當中需要將圖片保存到共享對象當中&#xff0c;開始用了倆天的時間做了對象的序列化&#xff0c;并以BitmapData的形式進行了圖片的序列化保存共享&#xff0c;因為系統 沒有提供更好的接口所以…

java8自定義收集器_使用自定義收集器進行Java 8分組?

我有以下課程。class Person {String name;LocalDate birthday;Sex gender;String emailAddress;public int getAge() {return birthday.until(IsoChronology.INSTANCE.dateNow()).getYears();}public String getName() {return name;}}我希望能夠按年齡分組&#xff0c;然后收…

poj 1862 Stripies/優先隊列

原題鏈接&#xff1a;http://poj.org/problem?id1862 簡單題&#xff0c;貪心優先隊列主要練習一下stl大根堆 寫了幾種實現方式寫成類的形式還是要慢一些。。。 手打的heap&#xff1a; 1&#xff1a; 1 #include<cstdio>2 #include<cstdlib>3 #include<cmath&…

java url下載ics_使用Microsoft Graph API處理外部(Internet / .ics)日歷URL

在新的Graph API中&#xff0c;是否可以根據外部.ics日歷網址為用戶創建新日歷&#xff1f;我d like to do is to use a daemon to inject a link to an external calendar into the list of calendars a user has if they don已經有了這樣一個鏈接 . 這將有效地復制用戶可以在…

命令行生成jar文件

1.打開cmd&#xff0c;進入編譯完后所有類的當前目錄 命令行 jar -cvf javaname.jar *.class 這時已經生成了 javaname.jar 不過如果有多個類&#xff0c;雙擊打不開 2.解壓javaname.jar 進入META-INF&#xff0c;編輯MANIFEST.MF: 尾行寫入Main-Class:&#xff08;&…

Github鏈接地址

https://github.com/kzj1/test轉載于:https://www.cnblogs.com/lalal/p/4456923.html

java foreach和for循環區別_java相關:老生常談foreach(增強for循環)和for的區別

java相關&#xff1a;老生常談foreach(增強for循環)和for的區別發布于 2020-8-18|復制鏈接下面小妖就為大家帶來一篇老生常談foreach(增強for循環)和for的區別。小妖覺得挺不錯的&#xff0c;現在就分享給大家&#xff0c;也給大家做個參考。一起跟隨小妖過來看看吧首先說一下f…

關于事件冒泡和捕獲的問題

由于習慣于jquery的方便操作&#xff0c;往往讓我們慢慢淡忘了原生js應有的功能和屬性&#xff0c;今天重溫一下事件冒泡和捕獲問題。 冒泡&#xff1a;從內向外&#xff0c;如&#xff1a;div > body > html (不同瀏覽器稍有不同) 捕獲&#xff1a;從外向內&#xff0c;…

root無法運行命令解決辦法

今天運行一個命令wget(wg再使用tab鍵無法使用)&#xff0c;如下提示 -bash: /usr/bin/wget: 權限不夠 [rootwww /]# ls -Z /usr/bin/wget-rw-r--r--. root root system_u:object_r:bin_t:s0 /usr/bin/wget發現沒有執行權限 chmod x /usr/bin/wget -bash: /usr/bin/wget: …

java類編寫sql_用JavaBean編寫SQL Server數據庫連接類

以下為引用的內容&#xff1a;//類conn.db.conndb.javapackage conn.db;import java.sql.*;public class conndb {Connection conn;ResultSet rs;private int count;public conndb() {try {Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");} catch (Exception ex) {}…

ASP.NET中Request.ApplicationPath、Request.FilePath、Request.Path、.Request.MapPath、

1.Request.ApplicationPath->當前應用的目錄 Jsp中, ApplicationPath指的是當前的application(應用程序)的目錄,ASP.NET中也是這個意思。 對應的--例如我的服務器上有兩個web應用域名都是mockte.com 一個映射到目錄mockte.com/1/ 另一個影射到 http://mockte.com/2/ …

java timezone id_java.util.TimeZone.setID()方法實例

全屏setID(String ID)方法被用于設置時區ID。這不會改變的時區對象中的任何其他數據。聲明以下是java.util.TimeZone.setID()方法的聲明。public void setID(String ID)參數ID--這是新的時區ID。返回值NA異常NA例子下面的例子顯示java.util.TimeZone.setID()方法的使用package …

c語言中賦值截斷

在c語言中進行變量賦值的時候&#xff0c;如果將字節多的數據類型賦給一個占字節少的變量類型&#xff0c;會發生“截斷”。 發生這種情況的原因是&#xff1a;在賦值過程中只將占字節較長的變量的地位賦給占字節較少的變量。 如&#xff1a; int i345&#xff1b; char c‘…

創建一個自己的GitHub,創建自己的開源項目

作者是一個大學在讀學生&#xff0c;自己在平時的學習中&#xff0c;GitHub上的開源項目給自己提供了很大的幫助。GitHub是目前使用最廣泛的分布式項目管理軟件&#xff0c;GitHub上面托管了許多非常優秀的開源項目。我覺得每一個從事IT行業都應該有一個屬于自己的GitHub。下面…

設計模式之行為型(1)-職責鏈模式(Chain)

設計模式之行為型(1)-職責鏈模式(Chain)轉載于:https://www.cnblogs.com/lihuali/p/7493415.html

php apache win7,win7安裝apache+php

轉自百度經驗1 系統環境與軟件1php5.5.6 下載鏈接&#xff1a;http://windows.php.net/download/#php-5.5推薦 V11 x64&#xff0c;也就是64bit的。2apache2.4&#xff0c;下載鏈接&#xff1a;http://www.apachelounge.com/download/同樣是推薦 V11&#xff0c;64位的。3前面提…