<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      頭文件中定義函數(shù)引發(fā)multiple definition

      本文引用了博文,感謝原文作者。

      問題:某個頭文件中聲明并定義了一個函數(shù),然后在多個源碼文件中調用該函數(shù),編譯鏈接時出現(xiàn)了該函數(shù) multiple definition 問題,在頭文件中添加了 #ifndef 頭也不行,經(jīng)過嘗試發(fā)現(xiàn)如果將該函數(shù)的聲明和定義分開到. h 和. cpp 文件之后問題消失,為什么不能將函數(shù)直接定義在. h 文件中呢?

      針對該問題,抽象出如下幾個問題:

      1. 頭文件中只可以放置函數(shù)聲明,不可以放置函數(shù)定義嗎?

      以下面的程序為例:

      #ifndef __a_h__
      
      #define __a_h__
      
      void funcA(void);   
      
      void funcA(void)    
      
      {}
      
      #endif
      
      #ifndef __b_h__
      
      #define __b_h__
      
      void funcB(void);
      
      #endif
      
      #include "b.h"
      
      #include "a.h"
      
      void funcB(void)
      
      {
      
          funcA();
      
      }
      
      #ifndef __c_h__
      
      #define __c_h__
      
      void funcC(void);
      
      #endif
      
      #include "c.h"
      
      #include "a.h"
      
      void funcC(void)
      
      {
      
          funcA();
      
      }
      
      #include "b.h"
      
      #include "c.h"
      
      int main(int argc, char* argv[])
      
      {
      
          funcB();
      
          funcC();
      
      return 0;
      
      }
      

      上述代碼編譯鏈接的時候編譯器(g++)會報如下錯誤:

      c.o: In function `funcA()':
      
      c.cpp:(.text+0x0): multiple definition of `funcA()'
      
      b.o:b.cpp:(.text+0x0): first defined here
      
      collect2: ld returned 1 exit status
      

      為什么編譯器在鏈接的時候會抱怨 “funcA() 重復定義”?
      其實本質問題就是 funcA 的定義被放在了 a.h 中,如果寫在 a.cpp 中,就不會有重復定義的問題。下面分析一下編譯過程都發(fā)生了什么,這樣更容易從編譯器的角度理解此問題。

      編譯器處理 include 指令很簡單粗暴,就是直接把頭文件中的內(nèi)容包含進來。所以 b.cpp、c.cpp 和 main.cpp 代碼展開后可以簡化為:

      void funcA(void);   
      
      void funcA(void)    
      
      {}
      
      void funcB(void);
      
      void funcB(void)
      
      {
      
          funcA();
      
      }
      
      void funcA(void);   
      
      void funcA(void)    
      
      {}
      
      void funcC(void);
      
      void funcC(void)
      
      {
      
          funcA();
      
      }
      
      void funcB(void);
      
      void funcC(void);
      
      int main(int argc, char* argv[])
      
      {
      
          funcB();
      
          funcC();
      
      return 0;
      
      }
      

      編譯的時候,C++ 是采用獨立編譯,就是每個 cpp 單獨編譯成對應的. o 文件,最后鏈接器再將多個. o 文件鏈接成可執(zhí)行程序。所以從編譯的時候,從各個 cpp 文件看,編譯沒有任何問題。但是能發(fā)現(xiàn)一個問題,b.o 中聲明和定義了一次 funcA(),c.o 中也聲明和定義 funcA(),這就是編譯器報重復定義的原因。有人可能會問,既然是從同一份文件 include 過來的函數(shù) funcA,那么定義都是同一份,為什么編譯器不會智能的處理一下,讓鏈接時候不報錯呢?
      其實編譯器鏈接的時候,并不知道 b.cpp 中定義的 funcA 與 c.cpp 中定義的 funcA 是同一個文件 include 過來的,它只會認為如果有兩份定義,而且這兩份定義如果實現(xiàn)不同,那么到底以哪個為準呢?既然決定不了,那就干脆報錯好了。

      2. 為什么有些頭文件中直接把函數(shù)定義都寫進去了?

      剛才的分析,可以得出結論:頭文件中只做變量和函數(shù)的聲明,而不要定義,否則就會有重復定義的錯誤。但是有幾種情況是例外的。

      • 內(nèi)聯(lián)函數(shù)的定義
      • 類(class)的定義
      • const 和 static 變量

      以上幾種可以在頭文件中定義,下面逐個進行解釋。
      內(nèi)聯(lián)的目的就是在編譯期讓編譯器把使用函數(shù)的地方直接替換掉,而不是像普通函數(shù)一樣通過鏈接器把地址鏈接上。這種情況,如果定義沒有在頭文件的話,編譯器是無法進行函數(shù)替換的。所以 C++ 規(guī)定,內(nèi)聯(lián)函數(shù)可以在程序中定義多次,只要內(nèi)聯(lián)函數(shù)定義在同一個 cpp 中只出現(xiàn)一次就行。
      按照這個理論,上述 a.h 簡單修改一下就可以避免重復定義了。

      #ifndef __a_h__
      
      #define __a_h__
      
      inline void funcA(void);   
      
      void funcA(void)    
      
      {}
      
      #endif
      

      此外,類(class)的定義,可以放在頭文件中。
      用類創(chuàng)建對象的時候,編譯器要知道對象如何布局才能分配內(nèi)存,因此類的定義需要在頭文件中。一般情況下,我們把類內(nèi)成員函數(shù)的定義放在 cpp 文件中,但是如果直接在 class 中完成函數(shù)聲明 + 定義的話,這種函數(shù)會被編譯器當作 inline 的,因此滿足上面 inline 函數(shù)可以放在頭文件的規(guī)則。但是如果聲明和定義分開實現(xiàn),但是都放在頭文件中,那就會報重復定義了!!
      const 和 static 變量,可以放在頭文件中。
      const 對象默認是 static 的,而不是 extern 的,所以即使放在頭文件中聲明和定義。多個 cpp 引用同一個頭文件,互相也沒有感知,所以不會導致重復定義。

      3. 模板函數(shù) / 類中要求頭文件中必須包含定義才能進行模板實例化,這種定義放在頭文件的情況會不會有問題?

      前面分析可知,頭文件中要么只有函數(shù)聲明,要么是含有 inline 函數(shù)的定義。但是模板的定義 (包括非 inline 函數(shù) / 成員函數(shù)) 要求聲明和實現(xiàn)都必須放在頭文件中,難道沒有 “重復定義” 的問題???
      答案當然是不會有問題(要不 template 早就被抱怨死了)。其實編譯器也考慮到會遇到類似的問題,在編譯器或連接器的某處已經(jīng)有防止重定義的處理了。這里參考 stackflow 中的答案:http://stackoverflow.com/questions/235616/multiple-definitions-of-a-function-template

      posted @ 2022-05-10 23:56  殉道者之殤  閱讀(776)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产成人啪精品视频免费网| 狠狠色噜噜狠狠狠狠av不卡| 午夜福利国产一区二区三区| 国产97色在线 | 免费| 成人亚洲一级午夜激情网| 国内少妇偷人精品视频| 无遮挡又黄又刺激的视频| 孕妇怀孕高潮潮喷视频孕妇| 人妻性奴波多野结衣无码| 国产在线观看播放av| 井研县| 亚洲精品欧美综合二区| 五月婷婷深开心五月天| 国产精品自拍中文字幕| 国产裸体无遮挡免费精品| 欧美在线观看www| 久久久精品人妻一区二区三区| 欧洲国产成人久久精品综合 | 五月丁香六月狠狠爱综合| 成人精品视频一区二区三区尤物| 日本大片在线看黄a∨免费| 亚洲欧洲精品一区二区| 黄色段片一区二区三区| 亚洲天堂久久一区av| 成人3D动漫一区二区三区| 日韩精品一区二区三区中文无码 | 久久久WWW成人免费精品| av在线播放无码线| 久久天天躁夜夜躁狠狠| 精品国产迷系列在线观看| 亚洲精品久久久久久无码色欲四季| 亚洲69视频| 国产真实交换配乱婬95视频| 中文字幕乱妇无码AV在线| 国产国产精品人体在线视| 少妇人妻偷人免费观看| 久久天天躁狠狠躁夜夜avapp| 自拍偷在线精品自拍偷99| 亚洲精品一区二区美女| 一本久道中文无码字幕av| 亚洲熟妇丰满多毛xxxx|