新手小心:c語言中強(qiáng)符號(hào)與弱符號(hào)的使用
更新時(shí)間:2013年05月23日 16:08:36 作者:
本篇文章適合新手。是對(duì)c語言中強(qiáng)符號(hào)與弱符號(hào)的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
聲明:下面的實(shí)例全部在linux下嘗試,window下未嘗試。有興趣者可以試一下。文章針c初學(xué)者。
c語言的強(qiáng)符號(hào)和弱符號(hào)是c初學(xué)者經(jīng)常容易犯錯(cuò)的地方。而且很多時(shí)候,特別是多人配合開發(fā)的程序,它引起的問題往往非常行為怪異而且難以定位。
什么是強(qiáng)符號(hào)和弱符號(hào)?
在c語言中,函數(shù)和初始化的全局變量是強(qiáng)符號(hào),未初始化的全局變量時(shí)弱符號(hào)。強(qiáng)符號(hào)和弱符號(hào)的定義是連接器用來處理多重定義符號(hào)的,它的規(guī)則是:
不允許多個(gè)強(qiáng)符號(hào);
如果一個(gè)強(qiáng)符號(hào)和一個(gè)弱符號(hào),這選擇強(qiáng)符號(hào);
如果多個(gè)弱符號(hào),則任意選一個(gè)。
它的陷阱:
上代碼:
//main.c
#include <stdio.h>
int fun();
int x;
int main()
{
printf("in main.c:x=%p\n", &x);
fun();
return 0;
}
//test.c
#include <stdio.h>
int x;
int fun()
{
printf("in test.c:x=%p\n", &x);
return 0;
}
編譯:gcc main.c test.c,運(yùn)行,結(jié)果:
in main.c:x=0x80496a8
in test.c:x=0x80496a8
兩個(gè)x是一個(gè)變量。這也許可以說的過去,可能一個(gè)忘記加extern了。
再看:
//main.c
#include <stdio.h>
int fun();
int x;
int main()
{
printf("in main.c:&x=%p\n", &x);
fun();
return 0;
}
//test.c
#include <stdio.h>
struct
{
<span style="white-space:pre"> </span>char a;
<span style="white-space:pre"> </span>char b;
<span style="white-space:pre"> </span>char c;
<span style="white-space:pre"> </span>char d;<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>int t;
} x;
int fun()
{
printf("in test.c:&x=%p\n", &x);
return 0;
}
運(yùn)行結(jié)果:
in main.c:&x=0x80496e0
in test.c:&x=0x80496e0
連接器還認(rèn)為他們是一個(gè)變量,這個(gè)時(shí)候程序員非常可能認(rèn)為他們是兩個(gè)變量(或者說優(yōu)秀的程序員會(huì))。而事實(shí)卻相反,同一塊內(nèi)存,在不同的文件中會(huì)有不同的類型和含義。這兩個(gè)文件對(duì)這塊內(nèi)存讀寫的過程中,都會(huì)影響到對(duì)方,引發(fā)非常詭異的問題。
設(shè)想一下,如果是一個(gè)程序同時(shí)又多個(gè)人員來開發(fā),如果他們只有有一個(gè)全局變量重名,且沒有初始化,那么就會(huì)引發(fā)問題了。
在一個(gè)程序中出現(xiàn)問題還算好,畢竟代碼都在一起。如果你使用的動(dòng)態(tài)庫或者靜態(tài)庫中有未初始化的全局變量,并且恰好也和你定義的重名,結(jié)果如何?我嘗試過,和上面一樣,沖突的兩個(gè)變量地址也相同。而這個(gè)時(shí)候你如果沒有庫的源碼,當(dāng)發(fā)生了問題,變量被修改,你估計(jì)要走很多彎路才能想到是庫改了你的變量。這是我曾經(jīng)解決過的一個(gè)問題。從那之后,我要求我們公司所有庫的源碼中不可以出現(xiàn)非static全局變量。
如何避免?
1、上策:想辦法消除全局變量。全局變量會(huì)增加程序的耦合性,對(duì)他要控制使用。如果能用其他的方法代替最好。
2、中策:實(shí)在沒有辦法,那就把全局變量定義為static,它是沒有強(qiáng)弱之分的。而且不會(huì)和其他的全局符號(hào)產(chǎn)生沖突。至于其他文件可能對(duì)他的訪問,可以封裝成函數(shù)。把一個(gè)模塊的數(shù)據(jù)封裝起來是一個(gè)好的實(shí)踐。
3、下策:把所有的符號(hào)全部都變成強(qiáng)符號(hào)。所有的全局變量都初始化,記住,是所有的。如果一個(gè)沒有初始化,就可能會(huì)和其他人產(chǎn)生沖突,盡管別人初始化了。(自己寫代碼測試一下)。
4、必備之策:GCC提供了一個(gè)選項(xiàng),可以檢查這類錯(cuò)誤:-fno-common。
c語言為什么設(shè)計(jì)它?
容易引發(fā)問題,怎么回事C的一個(gè)特性?可能是歷史的原因,沒有深究。但我認(rèn)為也可能是部分語言設(shè)計(jì)哲學(xué)的原因:c語言的設(shè)計(jì)哲學(xué)有一點(diǎn)就是充分的相信程序員,給他們最大的權(quán)利和靈活性。這個(gè)特性在某些特殊的情況下也許可能發(fā)揮作用。
語言中的君子和小人:
古人說要近君子,遠(yuǎn)小人。像今天說的這個(gè)特性(共同體也可以算一個(gè)),應(yīng)該是c語言中的“小人”(輕拍,可能說的比較重)。我們還是敬而遠(yuǎn)之的比較好。康熙好像說過,(特殊時(shí)期)治國不但要用君子,還要會(huì)用小人,但要能夠駕馭得當(dāng)。否則會(huì)引火燒身。
c語言的強(qiáng)符號(hào)和弱符號(hào)是c初學(xué)者經(jīng)常容易犯錯(cuò)的地方。而且很多時(shí)候,特別是多人配合開發(fā)的程序,它引起的問題往往非常行為怪異而且難以定位。
什么是強(qiáng)符號(hào)和弱符號(hào)?
在c語言中,函數(shù)和初始化的全局變量是強(qiáng)符號(hào),未初始化的全局變量時(shí)弱符號(hào)。強(qiáng)符號(hào)和弱符號(hào)的定義是連接器用來處理多重定義符號(hào)的,它的規(guī)則是:
不允許多個(gè)強(qiáng)符號(hào);
如果一個(gè)強(qiáng)符號(hào)和一個(gè)弱符號(hào),這選擇強(qiáng)符號(hào);
如果多個(gè)弱符號(hào),則任意選一個(gè)。
它的陷阱:
上代碼:
復(fù)制代碼 代碼如下:
//main.c
#include <stdio.h>
int fun();
int x;
int main()
{
printf("in main.c:x=%p\n", &x);
fun();
return 0;
}
//test.c
#include <stdio.h>
int x;
int fun()
{
printf("in test.c:x=%p\n", &x);
return 0;
}
編譯:gcc main.c test.c,運(yùn)行,結(jié)果:
in main.c:x=0x80496a8
in test.c:x=0x80496a8
兩個(gè)x是一個(gè)變量。這也許可以說的過去,可能一個(gè)忘記加extern了。
再看:
復(fù)制代碼 代碼如下:
//main.c
#include <stdio.h>
int fun();
int x;
int main()
{
printf("in main.c:&x=%p\n", &x);
fun();
return 0;
}
復(fù)制代碼 代碼如下:
//test.c
#include <stdio.h>
struct
{
<span style="white-space:pre"> </span>char a;
<span style="white-space:pre"> </span>char b;
<span style="white-space:pre"> </span>char c;
<span style="white-space:pre"> </span>char d;<span style="white-space:pre"> </span>
復(fù)制代碼 代碼如下:
<span style="white-space:pre"> </span>int t;
復(fù)制代碼 代碼如下:
} x;
int fun()
{
printf("in test.c:&x=%p\n", &x);
return 0;
}
運(yùn)行結(jié)果:
in main.c:&x=0x80496e0
in test.c:&x=0x80496e0
連接器還認(rèn)為他們是一個(gè)變量,這個(gè)時(shí)候程序員非常可能認(rèn)為他們是兩個(gè)變量(或者說優(yōu)秀的程序員會(huì))。而事實(shí)卻相反,同一塊內(nèi)存,在不同的文件中會(huì)有不同的類型和含義。這兩個(gè)文件對(duì)這塊內(nèi)存讀寫的過程中,都會(huì)影響到對(duì)方,引發(fā)非常詭異的問題。
設(shè)想一下,如果是一個(gè)程序同時(shí)又多個(gè)人員來開發(fā),如果他們只有有一個(gè)全局變量重名,且沒有初始化,那么就會(huì)引發(fā)問題了。
在一個(gè)程序中出現(xiàn)問題還算好,畢竟代碼都在一起。如果你使用的動(dòng)態(tài)庫或者靜態(tài)庫中有未初始化的全局變量,并且恰好也和你定義的重名,結(jié)果如何?我嘗試過,和上面一樣,沖突的兩個(gè)變量地址也相同。而這個(gè)時(shí)候你如果沒有庫的源碼,當(dāng)發(fā)生了問題,變量被修改,你估計(jì)要走很多彎路才能想到是庫改了你的變量。這是我曾經(jīng)解決過的一個(gè)問題。從那之后,我要求我們公司所有庫的源碼中不可以出現(xiàn)非static全局變量。
如何避免?
1、上策:想辦法消除全局變量。全局變量會(huì)增加程序的耦合性,對(duì)他要控制使用。如果能用其他的方法代替最好。
2、中策:實(shí)在沒有辦法,那就把全局變量定義為static,它是沒有強(qiáng)弱之分的。而且不會(huì)和其他的全局符號(hào)產(chǎn)生沖突。至于其他文件可能對(duì)他的訪問,可以封裝成函數(shù)。把一個(gè)模塊的數(shù)據(jù)封裝起來是一個(gè)好的實(shí)踐。
3、下策:把所有的符號(hào)全部都變成強(qiáng)符號(hào)。所有的全局變量都初始化,記住,是所有的。如果一個(gè)沒有初始化,就可能會(huì)和其他人產(chǎn)生沖突,盡管別人初始化了。(自己寫代碼測試一下)。
4、必備之策:GCC提供了一個(gè)選項(xiàng),可以檢查這類錯(cuò)誤:-fno-common。
c語言為什么設(shè)計(jì)它?
容易引發(fā)問題,怎么回事C的一個(gè)特性?可能是歷史的原因,沒有深究。但我認(rèn)為也可能是部分語言設(shè)計(jì)哲學(xué)的原因:c語言的設(shè)計(jì)哲學(xué)有一點(diǎn)就是充分的相信程序員,給他們最大的權(quán)利和靈活性。這個(gè)特性在某些特殊的情況下也許可能發(fā)揮作用。
語言中的君子和小人:
古人說要近君子,遠(yuǎn)小人。像今天說的這個(gè)特性(共同體也可以算一個(gè)),應(yīng)該是c語言中的“小人”(輕拍,可能說的比較重)。我們還是敬而遠(yuǎn)之的比較好。康熙好像說過,(特殊時(shí)期)治國不但要用君子,還要會(huì)用小人,但要能夠駕馭得當(dāng)。否則會(huì)引火燒身。
相關(guān)文章
對(duì)比分析C語言中的gcvt()和ecvt()以及fcvt()函數(shù)
這篇文章主要介紹了對(duì)比分析C語言中的gcvt和ecvt以及fcvt函數(shù),都是將數(shù)字轉(zhuǎn)化為字符串,注意其之間的功能區(qū)別,需要的朋友可以參考下2015-08-08
VS Code遠(yuǎn)程連接Linux服務(wù)器調(diào)試C程序的操作方法
這篇文章主要介紹了VS Code遠(yuǎn)程連接Linux服務(wù)器調(diào)試C程序的操作方法,打開遠(yuǎn)程 Linux 服務(wù)器上的文件夾本文以 /root/ 為例,給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-12-12
VC++實(shí)現(xiàn)通過API來查看程序錯(cuò)誤信息的方法
這篇文章主要介紹了VC++實(shí)現(xiàn)通過API來查看程序錯(cuò)誤信息的方法,非常實(shí)用的功能,需要的朋友可以參考下2014-08-08
在C++17中實(shí)現(xiàn)無鎖數(shù)據(jù)結(jié)構(gòu)的方法詳解
在探索?C++17?中的無鎖數(shù)據(jù)結(jié)構(gòu)之前,我們首先需要理解無鎖編程的基本概念及其在現(xiàn)代軟件開發(fā)中的重要性,在這個(gè)章節(jié)中,我們將深入探討無鎖編程的概念,以及它如何滿足人類對(duì)于更高效、更可靠軟件的本能需求,文中通過代碼示例介紹的非常詳細(xì),感興趣的朋友可以參考下2023-12-12
C語言數(shù)據(jù)結(jié)構(gòu)中定位函數(shù)Index的使用方法
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)中定位函數(shù)Index的使用方法的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解這部分內(nèi)容,需要的朋友可以參考下2017-10-10
C++計(jì)算任意權(quán)值的單源最短路徑(Bellman-Ford)
這篇文章主要為大家詳細(xì)介紹了C++計(jì)算任意權(quán)值的單源最短路徑,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
C++實(shí)現(xiàn)LeetCode(41.首個(gè)缺失的正數(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(41.首個(gè)缺失的正數(shù)),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07

