自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C開發(fā)中段錯(cuò)誤的三種調(diào)試方法

開發(fā) 后端
之前我們有分享總線錯(cuò)誤的例子:Linux軟件開發(fā)中,總線錯(cuò)誤的坑?替大家先踩一步。

大家好,我是雜燴君。

嵌入式C開發(fā),或多或少都遇到段錯(cuò)誤(segmentation fault )。

段錯(cuò)誤相比于總線錯(cuò)誤,是一種更常見的錯(cuò)誤。

段錯(cuò)誤是怎么產(chǎn)生的呢?

段錯(cuò)誤是因?yàn)樵L問不可訪問的內(nèi)存產(chǎn)生的。

下面是一些典型的段錯(cuò)誤產(chǎn)生的原因:

  • 訪問不存在的內(nèi)存地址
  • 訪問只讀的內(nèi)存地址
  • 棧溢出
  • 內(nèi)存越界
  • ……

段錯(cuò)誤實(shí)例

1、實(shí)例1:訪問不存在的內(nèi)存地址

#include <stdio.h>
int main(int argc, char **argv)
{
printf("==================segmentation fault test==================\n");
int *p = NULL;
*p = 1234;
return 0;
}

2、實(shí)例2:訪問只讀的內(nèi)存地址

#include <stdio.h>
int main(int argc, char **argv)
{
printf("==================segmentation fault test1==================\n");
char *str = "hello";
str[0] = 'H';
return 0;
}

3、實(shí)例3:棧溢出

#include <stdio.h>
static void test(void)
{
char buf[1024 * 1024] = {0};
static int i = 0;
i++;
printf("i = %d\n", i);
test();
}
int main(int argc, char **argv)
{
printf("==================segmentation fault test2==================\n");
test();
return 0;
}

4、實(shí)例4:內(nèi)存越界
#include <stdio.h>
int main(int argc, char **argv)
{
printf("==================segmentation fault test3==================\n");
static char arr[5] = {0, 1, 2, 3, 4};
printf("arr[10000] = %d\n", arr[10000]);
return 0;
}

段錯(cuò)誤調(diào)試方法

從上面的幾個(gè)例子中,我們應(yīng)該對(duì)段錯(cuò)誤有了一定的認(rèn)識(shí),但實(shí)際項(xiàng)目中,實(shí)際中,段錯(cuò)誤可能沒有上面的例子那么明顯看出。如果之前沒有這方面的經(jīng)驗(yàn),可能一時(shí)半會(huì)也定位不到問題。下面分享段錯(cuò)誤的3種調(diào)試方法供大家參考。

我們依舊使用例子來說明,例子:

#include <stdio.h>
static void func0(void)
{
printf("This is func0\n");
int *p = NULL;
*p = 1234;
}
static void func1(void)
{
printf("This is func1\n");
func0();
}
int main(int argc, char **argv)
{
printf("==================segmentation fault test4==================\n");
func1();
return 0;
}

1、gdb一步步運(yùn)行

使用gdb調(diào)試,打一些斷點(diǎn)、按流程運(yùn)行下去,運(yùn)行到段錯(cuò)誤的地方會(huì)直接提示報(bào)錯(cuò)。

或者使用命令行直接gdb調(diào)試:

這里我們是在x86上運(yùn)行,如果是定位arm嵌入式Linux程序,我們?cè)趺醋龅模?/p>

同樣也是可以使用gdb的,可以參考我們之前分享的文章:VSCode+gdb+gdbserver遠(yuǎn)程調(diào)試ARM程序

2、通過core文件

Linux下,一個(gè)程序崩潰時(shí),它一般會(huì)在指定目錄下生成一個(gè)core文件。core文件僅僅是一個(gè)內(nèi)存映象(同時(shí)加上調(diào)試信息),主要是用來調(diào)試的。

core文件可打開與關(guān)閉。相關(guān)命令:

ulimit -c   # 查看core文件是否打開
ulimit -c 0 # 禁止產(chǎn)生core文件
ulimit -c unlimited #設(shè)置core文件大小為不限制大小
ulimit -c 1024 #限制產(chǎn)生的core文件的大小不能超過1024KB

0代表關(guān)閉。下面我們打開它:

運(yùn)行程序時(shí),程序崩潰時(shí),在程序目錄下會(huì)生成core文件,如:

調(diào)試core文件:

gdb test core

3、利用backtrace進(jìn)行分析

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <execinfo.h>
void func0(void)
{
printf("This is func0\n");
int *p = NULL;
*p = 1234;
}
void func1(void)
{
printf("This is func1\n");
func0();
}
void func2(void)
{
printf("This is func2\n");
func1();
}
void dump(int signo)
{
void *array[100];
size_t size;
char **strings;
size = backtrace(array, 100);
strings = backtrace_symbols(array, size);
printf("Obtained %zd stacks.\n", size);
for(int i = 0; i < size; i++)
{
printf("%s\n", strings[i]);
}

free(strings);
exit(0);
}
int main(int argc, char **argv)
{
printf("==================segmentation fault test5==================\n");
signal(SIGSEGV, &dump);
func2();
return 0;
}

當(dāng)程序發(fā)生段錯(cuò)誤時(shí),內(nèi)核會(huì)向程序發(fā)送SIGSEGV信號(hào)。dump為SIGSEGV信號(hào)處理函數(shù),其實(shí)現(xiàn)用到了execinfo.h里的兩個(gè)函數(shù):

int backtrace(void **buffer,int size);
char ** backtrace_symbols (void *const *buffer, int size);

backtrace函數(shù)用于獲取當(dāng)前線程的調(diào)用堆棧,獲取的信息將會(huì)被存放在buffer中,它是一個(gè)指針列表。參數(shù) size 用來指定buffer中可以保存多少個(gè)void* 元素。函數(shù)返回值是實(shí)際獲取的指針個(gè)數(shù),最大不超過size大小 在buffer中的指針實(shí)際是從堆棧中獲取的返回地址,每一個(gè)堆??蚣苡幸粋€(gè)返回地址。

backtrace_symbols將從backtrace函數(shù)獲取的信息轉(zhuǎn)化為一個(gè)字符串?dāng)?shù)組。參數(shù)buffer應(yīng)該是從backtrace函數(shù)獲取的指針數(shù)組,size是該數(shù)組中的元素個(gè)數(shù)(backtrace的返回值)。函數(shù)返回值是一個(gè)指向字符串?dāng)?shù)組的指針,它的大小同buffer相同。

每個(gè)字符串包含了一個(gè)相對(duì)于buffer中對(duì)應(yīng)元素的可打印信息。它包括函數(shù)名,函數(shù)的偏移地址,和實(shí)際的返回地址。注意:該函數(shù)的返回值是通過malloc函數(shù)申請(qǐng)的空間,因此調(diào)用者必須使用free函數(shù)來釋放指針。如果不能為字符串獲取足夠的空間函數(shù)的返回值將會(huì)為NULL。

以上就是本次介紹的三種定位段錯(cuò)誤問題的方法,可以定位不同程度的問題。

責(zé)任編輯:龐桂玉 來源: C語言與C++編程
相關(guān)推薦

2009-10-14 14:37:56

調(diào)試.NET程序

2021-06-07 08:00:00

開發(fā)集成API

2009-09-08 10:37:57

C#遍歷CheckBo

2022-12-07 10:20:08

藍(lán)牙物聯(lián)網(wǎng)

2017-10-18 15:30:47

數(shù)據(jù)中心錯(cuò)誤方法

2019-08-30 17:24:41

microservic微服務(wù)

2009-08-26 18:10:44

C# using的用法

2009-07-30 16:27:33

C#比較時(shí)間

2009-07-08 12:56:32

編寫Servlet

2020-09-08 12:53:47

C++數(shù)據(jù)線程

2024-12-03 00:40:55

2009-08-20 17:30:02

C#連接字符串

2022-11-30 15:15:48

2009-05-07 15:02:42

OracleJoin查詢

2009-12-09 09:48:38

solaris靜態(tài)路由

2011-06-10 10:43:12

Ubuntu應(yīng)用安裝

2022-03-04 14:52:27

云計(jì)算開源

2009-06-23 10:45:18

Hibernate支持

2009-08-06 15:26:18

C#異常類型

2022-05-30 07:07:35

Java監(jiān)聽文件Java 8
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)