C語言的那些小秘密之函數的調用關係

2021-01-07 電子產品世界

  顯示函數的調用關係是調試器的必備功能,如果我們在程序的運行中出現了崩潰的情況,通過函數的調用關係可以快速定位問題的根源,懂得函數調用關係的實現原理也可以擴充自己的知識面,在沒有調試器的情況下,我們也可以自己來實現顯示函數的調用關係。在我們自己動手寫backtrace函數之前,先來看看glibc提供的backtrace函數的使用。代碼如下:

本文引用地址:http://www.eepw.com.cn/article/270700.htm

  #include

  #include

  #include

  #define MAX_LEVEL 4

  static void call2()

  {

  int i = 0;

  void* buffer[MAX_LEVEL] = {0};

  int size=backtrace(buffer, MAX_LEVEL);

  for(i = 0; i < size; i++)

  {

  printf("called by %p\n", buffer[i]);

  }

  return;

  }

  static void call1()

  {

  call2();

  return;

  }

  static void call()

  {

  call1();

  return;

  }

  int main(int argc, char* argv[])

  {

  call();

  return 0;

  }

  在此先講解下backtrace()函數的使用:

  int backtrace(void **buffer,int size)

  該函數用來獲取當前線程的調用堆棧,獲取的信息將會被存放在buffer中,它是一個指針列表。參數 size 用來指定buffer中可以保存多少個void* 元素。函數返回值是實際獲取的指針個數,最大不超過size大小,在buffer中的指針實際是從堆棧中獲取的返回地址,每一個堆棧框架有一個返回地址。

  接下來的任務就是編譯運行了。

  root@ubuntu:/home/shiyan# gcc -g -Wall sss.c -o p

  root@ubuntu:/home/shiyan# ./p

  輸出結果為:

  called by 0x8048440

  called by 0x804847d

  called by 0x804848a

  called by 0x8048497

  上面的運行結果就是調用者的地址,看起來還不是那麼的直觀,我們使用addr2line工具來實現地址到原始碼位置的轉換。

  運行

  root@ubuntu:/home/shiyan# ./p |awk '{print "addr2line "$3" -e p"}'>t.sh;. t.sh;rm -f t.sh

  輸出結果為:

  /home/shiyan/sss.c:12

  /home/shiyan/sss.c:27

  /home/shiyan/sss.c:34

  /home/shiyan/sss.c:40

  接下來看看在棧中數據的結構。

  

c語言相關文章:c語言教程


相關焦點

  • C語言的那些小秘密之預處理
    宏替換在編譯前進行,不分配內存  (4)宏的啞實結合(所謂的啞實結合類似於函數調用過程中實參替代形參的過程)不存在類型,也沒有類型轉換。,可以看出這個時候函數並沒有被調用,這是因為我們使用了#define print() ((void)(3)),使得之後調用函數print()轉換為了一個空操作,所以這個函數在接下來的代碼中都不會被調用了,就像被「衝刷掉」了一樣。
  • C語言的那些小秘密之函數指針
    我們經常會聽到這樣的說法,不懂得函數指針就不是真正的C語言高手。我們不管這句話對與否,但是它都從側面反應出了函數指針的重要性,所以我們還是有必要掌握對函數指針的使用。先來看看函數指針的定義吧。本文引用地址:http://www.eepw.com.cn/article/270442.htm  函數是由執行語句組成的指令序列或者代碼,這些代碼的有序集合根據其大小被分配到一定的內存空間中,這一片內存空間的起始地址就成為函數的地址,不同的函數有不同的函數地址,編譯器通過函數名來索引函數的入口地址,為了方便操作類型屬性相同的函數,c/c++引入了函數指針,函數指針就是指向代碼入口地址的指針
  • C語言的那些小秘密之異常處理
    如果我們在上面的代碼中稍作修改,在setjmp()函數的調用之前調用longjmp()函數,我們發現此時沒有任何的輸出,程序直接崩潰掉退出了。  接下來我們來看看一個函數的使用,如果對於這個函數不理解的讀者,可以多看幾次我給出的模擬該函數的實現代碼。
  • 為何C語言函數調用要堆棧,而彙編卻不需要?
    上下文,英文叫做context,就是上面的文章,和下面的文章,即與你此刻,當前CPU運行有關係的內容,即那些你用到寄存器。所以,和上面的現場,是一個意思。保存寄存器的值,一般用的是push指令,將對應的某些寄存器的值,一個個放到堆棧中,把對應的值壓入到堆棧裡面,即所謂的壓棧。
  • C語言函數調用過程中的內存變化解析
    相信很多編程新手村的同學們都會有一個疑問:C 語言如何調用函數的呢?局部變量的作用域為什麼僅限於函數內?這個調用不是指C 語言上的函數調用的語法,而是在內存的視角下,函數的調用過程。本文將從C 語言調用實例,內存視角,反彙編代碼來探討C 語言函數的調用過程,也可以說是C 語言函數調用過程圖解。通過這個C 語言函數調用過程圖解,同學們將會知道,C 語言函數在調用時,內存空間是怎樣變化的。 要想理解這一個過程還好涉及到函數棧幀的概念。
  • 傳智播客:C語言函數對另外一個源文件函數進行調用(外部函數)
    前面文章關於函數的調用都是針對一個源文件中其他函數進行調用的,想要學習函數調用的可以看上一篇文章。有些情況下,函數是可能對另外一個源文件中的函數進行調用的。當一個程序由多個源文件組成的時候,根據函數是否能被其他源文件調用的時候,將函數分為內部函數和外部函數,本文就會圍著這外部函數的特點進行講解,希望每一個在學C語言的小夥伴都能弄懂函數的知識點。
  • C語言的那些小秘密之斷言
    在以上代碼的開頭部分我們把#define NDEBUG給注釋掉了,所以我們啟用了assert,main函數中使用了assert(copy_string(str,dec_str));來實現copy_string函數的調用
  • C語言的那些小秘密之字節對齊
    按照預先的計劃安排,這次應該是寫《C語言的那些小秘密之鍊表(三)》的,但是我發現如果直接開始講解linux內核鍊表的話,可能有些地方如果我們不在此做一個適當的講解的話,有的讀者看起來可能難以理解,所以就把字節對齊挑出來另寫一篇博客,我在此儘可能的講解完關於字節對齊的內容,希望我的講解對你有所幫助。
  • Python使用ctypes模塊調用DLL函數之C語言數組與numpy數組傳遞
    在Python語言中,可以使用ctypes模塊調用其它如C++語言編寫的動態連結庫DLL文件中的函數,在提高軟體運行效率的同時,也可以充分利用目前市面上各種第三方的DLL庫函數,以擴充Python軟體的功能及應用領域,減少重複編寫代碼、重複造輪子的工作量,這也充分體現了
  • C語言的那些小秘密之變參函數的實現
    在學習C語言的過程中我們可能很少會去寫變參函數,印象中大學老師好像也沒有提及過,但我發現變參函數的實現很巧妙,所以還是特地在此分析下變參函數的實現原理
  • C語言之函數
    一.函數的概念1.C語言中,最簡單的程序模塊就是函數。2.函數被視為程序設計的基本邏輯單位,一個c程序是由一個main()函數和若干其他函數組成。3.程序執行從main()函數開始,main()函數可以調用其他函數,其他函數可以互相調用。
  • C語言函數的調用 - 百度經驗
    在實際工程項目中,一個程序通常都是由很多個子程序模塊組成的,一個模塊實現一個特定的功能,在 C 語言中,這個模塊就用函數來表示。一個 C 程序一般由一個主函數和若干個其他函數構成。主函數可以調用其它函數,其它函數也可以相互調用,但其它函數不能調用主函數。在我們的 51 單片機程序中,還有中斷服務函數,是當相應的中斷到來後自動調用的,不需要也不能由其它函數來調用。
  • C語言的那些小秘密之volatile
    在開始講解volatile之前我們先來講解下接下來要用到的一個函數,知道如何使用該函數的讀者可以跳過該函數的講解部分。我們在此主要的是關注前一個成員變量timeval,後一個我們在此不使用,所以使用gettimeofday()函數的時候我們把有一個參數設定為NULL,下面先來看看一段簡單的代碼。
  • C語言函數指針之回調函數
    我的理解是:把一段可執行的代碼像參數傳遞那樣傳給其他代碼,而這段代碼會在某個時刻被調用執行,這就叫做回調如果代碼立即被執行就稱為同步回調,如果過後再執行,則稱之為異步回調回調函數就是一個通過調用的函數。
  • C語言的那些小秘密之動態數組
    不管什麼情況下通通使用靜態數組的方法來解決,在當初學習C語言的時候我就是一個典型的例子,但是現在發現這是一個相當不好的習慣,甚至可能導致編寫的程序出現一些致命的錯誤。  請輸入所要創建的一維動態數組的長度:4  0 0 0 0  1 2 3 4 Press any key to continue  在此我使用的是calloc()函數來分配的,同時也使用兩個for語句來列印數組元素,我們發現第一個列印輸出的數組元素值均為0,在此也是為了加深讀者對於calloc()函數的印象我特地使用了它來分配,如果對於calloc
  • C語言(新手)kbhit()函數的調用
    C語言#C語言初學#這個函數C語言裡面有很多函數,每個函數都有一些獨特的功能。有些函數功能非常強大還很有趣,了解遊戲函數的功能對編程非常有幫助的。在C語言中我們調用函數都有先聲明一個頭文件。畢竟我是新手嘛,遇見好玩的函數就像分享一下。
  • C語言 | 選擇1或2調用max或min
    在編程方面有著天賦異稟的人畢竟是少數,我們大多數人想要從C語言小白進階到高手,需要經歷的是日積月累的學習。那麼如何學習呢?當然是每天都練習一道C語言題目!!作者閆小林白天搬磚,晚上做夢。我有故事,你有酒麼?例36:C語言實現輸入兩個整數,然後讓用戶選擇1或者2,選擇1是調用max,輸出兩者中的大數,選擇2是調用min,輸出兩者中的小數。
  • Java通過-jni調用c語言
    在Ubuntu14.04中通過Java調用c語言(1)首先編寫一個簡單的Java程序。該文件中定義了c的函數原型。在實現c函數的時候需要。JNI調用的。(5)編寫c語言去實現這些方法,一個簡單的代碼如下:        #include <stdio.h>         #include "TestJNI.h"         int i=0;         JNIEXPORT void JNICALL Java_TestJNI_set (JNIEnv * env, jobject obj, jint j)
  • 傳智播客:C語言當中內部函數調用的方法和代碼格式
    內部函數由上一個小節講解的外部函數可以知道,只要聲明一個函數的原型就可以調用其他的源文件中的函數。但是當多個人參與開發一個項目的時候,有很大的可能會出現函數的重名的情況,這樣的話不同源文件的重名的函數就會互相干擾。
  • C語言函數調用棧(二)
    6. pascal調用約定Pascal語言調用約定,參數按照從左至右的順序入棧。Pascal語言只支持固定參數的函數,參數的類型和數量完全可知,故由被調函數自身清理堆棧。pascal調用約定輸出的函數名稱無任何修飾且全部大寫。