關於分析VC++的一個報錯:error LNK2019: 無法解析的外部符號 __imp__。。。。。。

提前說明一下,我這個問題跟網上很多網友分享的問題不太一樣,而且我認爲導致問題出現的原因不重要,重點在於我分析這個問題的過程用到了一些知識,我認爲值得分享一下。

博客中用的到工程:https://download.csdn.net/download/xundao255/11264177 

(如果有經驗的話,完全可以根據博客內容自己創建工程,畢竟下載工程是需要C幣的。補充:我沒找到怎麼免C幣下載資源,這個C幣是系統自動設置的)

一、先列出源碼和錯誤截圖

#include <stdio.h>

int PrintString(unsigned int);

int main()
{
	PrintString(3);

	return 0;
}

PrintString(unsigned int)函數是“lib.lib”靜態庫中實現的函數,所以需要在工程的屬性中隱性導入這個靜態庫。注意:這個靜態庫是存放在當前工程的路徑下的。下面是編譯失敗的結果圖:

注意上面截圖的粗框線標註的函數“_PrintString”,這是編譯器編譯代碼後,會按照固定規則修改函數名。上面的錯誤信息表示找不到函數的實現,也就是定義。

二、再來看一下實驗用的lib靜態庫代碼

#include <stdio.h>

int __stdcall PrintString(unsigned int a)
{
	if (a < 5)
	{
		printf("小於5!\n");
	}
	else if (a == 5)
	{
		printf("等於5!\n");
	}
	else
	{
		printf("大於5!\n");
	}

	return 0;
}

這裏放出代碼,是爲了說明函數什麼功能,以及讀者能自己做這個實驗。在本博客中,我是假設不知道源代碼的,只知道函數接口的聲明而已和如何使用函數而已。

三、將步驟二中生成的“lib.lib”靜態庫放到步驟一的工程裏面,使編譯時能被找到。

四、當我發現出現了步驟一的錯誤後,逐漸排除了lib靜態庫沒有成功加載的情況,也確定不是函數名寫錯了。此時,我就想看一下lib靜態庫的函數接口是什麼樣的,很有可能問題就出在這裏。於是我再網上找到了方法,查看到lib靜態庫的接口信息:

Microsoft (R) COFF/PE Dumper Version 8.00.50727.42
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\Users\Administrator\Desktop\input_lib\input_lib\lib.lib

File Type: LIBRARY

Archive member name at 8: /               
5D16D10D time/date Sat Jun 29 10:46:37 2019
         uid
         gid
       0 mode
      9B size
correct header end

    4 public symbols

      1B8 ??_C@_07COGGELOH@?P?$KB?S?Z5?$CB?6?$AA@
      1B8 ??_C@_07KIEDOMAO@?$LF?H?S?Z5?$CB?6?$AA@
      1B8 ??_C@_07MOINBNDI@?$LE?s?S?Z5?$CB?6?$AA@
      1B8 _PrintString@4

Archive member name at E0: /               
5D16D10D time/date Sat Jun 29 10:46:37 2019
         uid
         gid
       0 mode
      9B size
correct header end

    1 offsets

        1      1B8

    4 public symbols

        1 ??_C@_07COGGELOH@?P?$KB?S?Z5?$CB?6?$AA@
        1 ??_C@_07KIEDOMAO@?$LF?H?S?Z5?$CB?6?$AA@
        1 ??_C@_07MOINBNDI@?$LE?s?S?Z5?$CB?6?$AA@
        1 _PrintString@4

  Summary

         92C .debug$S
          64 .debug$T
          D7 .drectve
          18 .rdata
           4 .rtc$IMZ
           4 .rtc$TMZ
          8B .text

仔細看裏面的函數接口顯示爲“_PrintString@4”,而不是“_PrintString”,這就解釋清楚爲什麼找不到這個函數了。

關於如何查看靜態庫的接口,見我的另一篇博客:https://blog.csdn.net/xundao255/article/details/94128402

五、關於爲什麼“PrintString”編譯成“_PrintString@4”,而不是“_PrintString”。

我們查看一下步驟二的代碼:int __stdcall PrintString(unsigned int a),函數聲明中加了“__stdcall”。這個關鍵字是給編譯器看的,告訴編譯器如何處理函數名稱,後邊的“@4”表示傳參的數據類型的字節長度。詳細說明見另一個大神寫的博客:https://www.cnblogs.com/songfeixiang/p/3733661.html

六、找到問題所在,我們在步驟一的代碼中的函數聲明添加上這個關鍵字,編譯成功並運行:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章