728x90

수성비전자방입니다. 오랜만에 Visual Studio Code에서 C프로그래밍 하는 것에 관한 글을 쓰겠습니다. C언어 디버깅을 하려면 어떡해야 할까요? gdb 디버거를 쓰시면 됩니다.^^

 

오늘 글을 시작하기 전에...

1. Visual Studio Code를 설치하시기 바랍니다. 오늘 다룰 내용은 VScode의 기능은 아니고 gdb 디버거의 기능이지만, 이 글의 시리즈가 Visual Studio Code 시리즈이므로 Visual Studio Code 기준으로 글을 작성하겠습니다.

https://toopyo.tistory.com/entry/vscode-post1

위 글을 보시면 Visual Studio Code를 설치하는 방법과 한국어 패치하는 방법을 확인하실 수 있습니다.

2. GCC를 설치하셔야 합니다. Windows PC라면 MinGW-w64를 설치하시면 됩니다.

https://toopyo.tistory.com/entry/vscode-post2

위 글을 참고하여 C/C++ 확장과 MinGW-w64를 설치하시고, C언어 빌드 옵션을 숙지하시기 바랍니다.

 

gdb 디버거를 사용하는 방법

1. C언어로 프로그래밍합니다. 저는 여러분들께 디버깅을 설명드리기 위해 위 스크린샷과 같이 간단하게 코드를 짜 보았습니다.

2. C code를 빌드합니다. 이때 -g 옵션을 꼭 추가하셔야 합니다. 디버깅을 위해 추가해야 할 옵션입니다.

예를 들어, 저는 gcc -g dtest.c -o appdt 명령을 실행했습니다.

(-o appdt는 실행파일명을 appdt로 지정한 것으로, PowerShell 자동완성 기능을 편하게 이용하기 위해 사용했습니다. 필수사항은 아닙니다.)

 

3. 빌드가 완료되면 exe 파일이 생성되었을 것입니다. 잘 생성되었는지 확인하시기 바랍니다.(실행파일명도 확인!)

4. 소스 코드와 실행 파일이 같은 폴더 안에 있어야 합니다.

5. gdb 실행파일명.exe 또는 gdb .\실행파일명.exe 명령을 실행합니다.

(Tip: 실행파일명의 일부만 치고 Tap 키를 누르면 .\실행파일명.exe로 자동완성됩니다.)

 

6. Type <return> to continue, or q <return> to quit

뜻: 계속하려면 엔터 키를 누르시고, 종료하려면 q를 입력하신 후 엔터 치세요.

 

이제 gdb 디버거가 실행되었습니다. 명령어를 입력하며 사용해야 하는데, 쓸만한 명령어들을 정리해 보겠습니다.

 

run

우선 가볍게 run부터 사용해 보겠습니다.

run을 입력하시고 엔터 치시면 프로그램이 실행됩니다.

지금은 딱히 설정한 것이 없어서 프로그램이 전부 실행되지만, breakpoint 설정을 하고 나서 다시 run을 해 보시면 breakpoint마다 쉬게 됩니다.(breakpoint에 대해서는 뒤에서 다룸.)

 

list

list는 소스코드를 볼 수 있는 명령어입니다.

*명령어: list

*기능: 소스코드 출력

 

list를 입력하시고 엔터 치시면 소스 코드의 Line 1부터 Line 10까지 출력됩니다. VScode로 작성한 것과 똑같죠?

 

엔터를 또 치시면 다음 10개 행(Line 11~20)이 출력됩니다. 엔터를 칠 때마다 열 줄씩 나오게 됩니다.

만약 list 명령을 실행했는데 소스 코드가 이상하게 나온다면, 빌드할 때 -g 옵션이 추가되지 않은 것이니, -g 옵션을 넣어서 다시 빌드하시기 바랍니다.

그나저나 VScode의 에디터로 소스 코드를 계속 확인할 수 있기 때문에 list 명령어는 잘 안 쓰시게 될 겁니다.

 

break

디버깅 하면 빠질 수 없는 기능 같습니다. breakpoint(정지점, 중단점)을 지정하는 기능이죠.

*명령어: break Line번호 또는 break 함수명

*기능: Breakpoint 지정

 

저는 함수명을 입력할 만한 게 없어서 Line 번호를 이용해 보았습니다.

break 7이라고 치니까

 

Breakpoint 1이 dtest.c의 line 7에 지정되었다고 나옵니다.

 

이제 run 명령을 실행하시면 Line 1~6를 실행하게 됩니다.

 

step

*명령어: step 또는 s

*기능: 현재 행 수행 후 정지. 함수 호출 시 함수 안으로 들어갑니다.

 

위 스크린샷은 Line 1~6까지 실행하고 현재 행이 Line 7인 상태에서 s 명령을 실행한 결과입니다.

Line 7인 printf("Hello world!\n");이 실행되었으며, Line 8은 공백이므로 현재 행이 Line 9으로 지정되었습니다.

 

next

*명령어: next 또는 n

*기능: 현재 행 수행 후 정지. 함수 호출 시 함수 수행 다음 행으로 넘어갑니다.

 

위 스크린샷은 Line 9까지 실행하고 현재 행이 Line 10인 상태에서 n 명령을 실행한 결과입니다.

Line 10인 b=2;가 실행되었으며, 현재 행이 Line 11으로 지정되었습니다.

제가 작성한 예시 코드에 main 함수 외에 다른 함수가 없어서 예를 잘 못 든 점 양해 부탁드립니다.(printf도 함수이긴 하지만 그건 stdio.h 안에 있는 함수라서...)

 

continue

*명령어: continue 또는 cont

*기능: Breakpoint(정지점)을 만날 때까지 수행

 

위 스크린샷은 Line 10까지 실행하고 현재 행이 Line 11인 상태에서 continue 명령을 실행한 결과입니다.

프로그램이 끝까지 실행되고 종료되었습니다.

 

whatis

*명령어: whatis 변수명

*기능: 변수의 type 출력

 

위 스크린샷은 Line 6까지 실행하고 현재 행이 Line 7인 상태에서 whatis a 명령을 실행한 결과입니다.

type = int 라고 출력되었습니다.

 

print

Logic error를 고치기 위해서 디버깅을 사용하다 보면 중간중간 변수의 값을 확인하고 싶을 때가 있을 것입니다. 그때마다 printf 함수를 이용할 수는 없으니 디버거의 print 기능을 이용합니다.

*명령어: print 변수명 또는 p 변수명

*기능: 변수에 저장된 현재 값을 한 번 출력

 

Line 6까지 실행하고 현재 행이 Line 7인 상태에서 print a 명령을 실행했더니 $1 = 0라고 출력되었습니다.

s 명령을 몇 번 해서 Line 9까지 실행하고 현재 행이 Line 10인 상태에서 print a 명령을 실행했더니 $2 = 1이 출력되었습니다.(Line 9가 a=1; 이었음.)

 

display

print는 변수의 값을 한 번만 출력합니다. Line별로 변하는 변수 값을 확인하고 싶다면 변수 값이 매번 출력되는 것이 좋겠죠? 그럴 때 사용할 수 있는 기능이 display입니다.

*명령어: display 변수명

*기능: 변수에 저장된 현재 값을 지속적으로 출력

 

위 스크린샷은 Line 9까지 실행하고 현재 행이 Line 10인 상태에서 display a 명령을 실행한 결과입니다.

1: d[1] = 0 이라고 출력되었습니다.

 

s 명령을 실행해서 Line 10까지 실행하고 현재 행이 Line 11인 상태가 되었습니다.

또 1: d[1] = 0 이라고 출력되었습니다.

 

눈에 띄는 변화를 보기 위해 Line 17에 Breakpoint를 지정하고 continue했습니다.

1: d[1] = 65 라고 출력되었습니다.(Line 13이 d[1]='A'이었음.)

 

set variable

*명령어: set variable 변수명 =

*기능: 변수 값을 변경

 

set variable d[1]=80 을 입력해 보았습니다.

엔터를 쳐도 어떤 메시지가 출력이 안 되는데요.

 

display 명령을 통해 확인해 보니 d[1] 값이 80으로 바뀌었네요. :)

 

info break

Breakpoint를 많이 지정하다 보면 자신이 어디에 Breakpoint를 지정했는지 잊어먹을 수 있죠. 이때 Breakpoint 목록을 확인하는 방법이 있습니다.

*명령어: info break

*기능: 설정되어 있는 Breakpoint 확인

 

이렇게 Breakpoint 목록을 확인하실 수 있습니다.

혹시 제거하고 싶은 Breakpoint가 있다면, Num 열과 What 열에 주목하세요!

 

delete

[특정 Breakpoint를 제거할 때]

*명령어: delete Num

(Num은 info break 명령을 통해서 확인)

*기능: 특정 Breakpoint 제거

 

Breakpoint 1이 dtest.c:7인 상태에서 delete 1 명령을 실행해 보았습니다.

 

run 명령을 실행했을 때 Breakpoint 2까지 실행되어, Line 16까지 실행되고 현재 행이 Line 18로 지정되었습니다.(Breakpoint2가 Line 17인데 현재 행이 Line 18인 이유: Line 17은 공백임.)

 

[모든 Breakpoint를 제거할 때]

*명령어: delete

*기능: 모든 Breakpoint 제거

 

1. delete를 입력하고 엔터 칩니다.

2. Delete all breakpoints? (y or n)이 출력되면 y를 입력하고 엔터 칩니다.

 

run을 실행해 보니 Breakpoint 없이 끝까지 실행됩니다.

 

kill

프로그램을 실행하다가 Breakpoint에서 멈췄을 때 오류를 발견한다면 빨리 종료하고 소스코드 수정을 하고 싶겠죠? 이때 프로그램을 종료하는 명령어가 있습니다.

*명령어: kill

*기능: 프로그램 수행 강제 종료

 

1. kill 명령을 실행합니다.

2. Kill the program being debugged? (y or n)이 출력되면 y를 입력하고 엔터키를 누릅니다.

3. 프로그램이 강제 종료되었습니다.

 

quit

디버거를 종료하고 싶을 때

*명령어: quit 또는 q

*기능: gdb 디버거 종료

 

q를 입력하고 엔터 쳤더니 위와 같이 gdb 디버거가 종료되었습니다.

 

저의 글을 읽어 주셔서 감사합니다.

글을 쓰고 보니 굉장히 길군요. 긴 글 읽어 주셔서 감사합니다.

다음에 만나요!

 

참고 자료

1) 슈라 Shuuura. 2020. "[우분투 리눅스] gcc컴파일 및 디버깅", 슈라의 인생 Log. :). (2021. 07. 24. 방문). https://blog.naver.com/sera3579/222109588968

2) 현애. 2020. "[20] 리눅스 - gcc 컴파일러, gdb 디버거", 과제하는 공대생. (2021. 07. 24. 방문). https://blog.naver.com/aeae_1/222161714082

3) KwonZales. 2021. "[Linux] 리눅스의 디버거, gdb의 디버거와 사용법", 하고 싶은 게 많은, 일단은 개발자. (2021. 07. 24. 방문). https://kwonzales.tistory.com/35

4) 허정호. 2017. "[과제] gdb(디버거) 사용법", 허정호의 IT 공장. (2021. 07. 24. 방문). https://hyess.tistory.com/337

 

댓글을 달아 주세요