static 함수 사용이유, atoi, strtol, getopt, gdb 사용법

sesame·2021년 12월 30일
0

교육

목록 보기
10/46
post-thumbnail

static 함수 사용이유
프로그램 내에서 중복되는 이름의 함수가 있을 수 있기 때문에 사용
static함수로 만들게 되면 .c 파일 내에서만 사용이 가능한 함수가 되기 때문에 이름 중복과 관련된 오류가 발생하지 않는다.

  • void 형 함수에서도 return; 을 쓸 수 있다.
    아무것도 반환하지 않는 return; 즉, 단지 함수를 종료시키기 위한 return;의 의미로 사용

문자열을 숫자로 변환하는 함수

atoi(3), atol(3)

int atoi(const char *str);  //문자열을 정수 타입으로
double atof(const char *str);  //문자열을 실수 타입으로
long atol(const char *str);  //문자열을 long 정수 타입으로

//atoi("문자만"); 0
//atoi("숫자만"); 2021
//atoi("숫자+문자"); 2021
//atoi("문자+숫자"); 0

return: 성공시 해당 정숫값, 실패/str에 정수가 포함되어있지 않은 경우 0

strtol, strtoll, strtod

//문자열을 long 값으로 변환 합니다. 2진수, 8진수, 16진수 값을 10진수로 변환 합니다. (string to long)
long strtol(const char *nptr, char **endptr, int base);
//nptr: NULL로 종결되는 수식을 포함하는 문자열의 포인터
//endptr: 변환이 멈춰진 문자열의 포인터
//base: 변환될 문자열의 기수(2, 8, 10, 16진수 선택) 2~36진수까지 가능
//return: 정수 값(long), 변환 실패시 0L 리턴. errno는 ERANGE로 설정
//		   -2,147,483,648 ~ 2,147,483,647


//문자열을 unsigned long 값으로 변환 합니다. (string to unsigned long)
unsigned long strtoul(const char *nptr, char **endptr, int base);
//nptr: NULL로 종결되는 수식을 포함하는 문자열의 포인터
//endptr: 변환이 멈춰진 문자열의 포인터
//base: 변환될 문자열의 기수(2, 8, 10, 16진수 선택) 2~36진수까지 가능
//return: 양의 정수 값(unsigned long), 변환 실패시 0L 리턴. errno는 ERANGE로 설정
//		   0~4,294,967,295


//문자열을 double 값으로 변환 합니다. (string to double)
double strtod(const char *nptr, char **endptr);
//nptr: NULL로 종결되는 수식을 포함하는 문자열의 포인터
//endptr: 변환이 멈춰진 문자열의 포인터
//return: 실수 값(double), 변환 실패시 0.0 리턴. errno는 ERANGE로 설정
//		   1.7E +/- 308 (15 digits)

long long int strtoll(string, &end, base);

옵션 해석 함수

getopt(3)

int getopt(int argc, char *const argv[], const char *optdecl);

extern char *optarg;
extern int optind, opterr, optopt;
  • getopt는 항상 루프와 함께 사용
  • 호출될 때마다 인자로 넘겨진 다음 옵션 문자를 반환
  • 잘못된 옵션일 경우 '?' return
  • 인자로 넘겨진 모든 옵션을 반환하면 -1 return(그래서 while문에 넣고 돌림)

argc, argv[]: main()의 인자를 그대로 전달
optdecl: 옵션에 해당하는 문자들을 하나의 문자열로 묶어서 지정

1) 파라미터를 취하지 않는 옵션
-a -t -x는 'atx'로 지정(이 때 문자 나열 순서는 결과에 영향 미치지 않는다.)

2) 파라미터를 받는 옵션
해당 옵션 문자 다음에 :(콜론)을 붙인다. 앞의 세가지 옵션을 더하여 파라미터값 받는 옵션 -f가 있다면 'af:tx'해도 되고 'f:atx' 또는 'atxf:'해도된다.

  • 전역 변수 'char *optarg'을 통해 파라미터 값을 얻을 수 있다.
    이 외에도 몇가지 전역 변수
  • char * optarg: 현재 처리 중인 옵션 파라미터(문자 다음에 오는 인수), 파라미터가 없는 경우 0(NULL)
  • int optind: 현재 처리 중인 옵션의 argv 인덱스
  • int optopt: 알 수 없는 옵션을 만났을 때 해당 옵션이 여기에 들어간다.(리턴값: ?)
  • int opterr: 에러 발생시 출력할지 말지를 정함(1(true)일때 출력)
//파라미터 값이 빠진채로 실행되었다면 이때는 옵션이 인식할 수 없는 옵션으로 처리된다.
//그래서 optopt값으로 확인할 수 있다.
if(optopt == 'w')
	printf("option -w requires FILENAME\n\n");


3) 파라미터로 -나 --를 넘겼을 때

  • --를 만나면 -1반환하여 while문 벗어난다.
    따라서 --는 getopt()에 의한 옵션 처리를 중지하고 프로그램에서 별도로 처리할 인자를 넘기고 싶을 때 사용
  • -를 만나면 옵션으로 인식하지 않고 다음 옵션으로 넘어감(주석처럼 무시)

getopt_long(3)

GNU libc에는 --로 시작하는 옵션을 해석하는 getopt_long()이 준비되어있다.

#define _GNU_SOURCE
#include <getopt.h>

int getopt_long(int argc, char * const argv[],
				const char * optdecl,  //검색하려는 짧은 옵션들의 문자열
                const struct option *longoptdecl,  //롱옵션의 정의
                int *longindex); //option에 해당되는 index 번호
                //*longindex에는 구조체 배열 중 몇 번째 option의 값이 검출되었는지를 알려주기 위해서 이 값이 함수 내에서 업데이트

//롱옵션의 정의
struct option{
	const char *name;//롱옵션의 이름: lines, help 등
    
    int has_arg;     
    //no_argument(또는 0): 파라미터를 취하지 않음
    //required_argument(또는 1): 반드시 파라미터를 취함
    //optional_argument(또는 2): 파라미터를 취할 수도 있음
                     
    int *flags;
    //옵션이 입력되었다면 지정한 값을 받을 수 있는 변수 주소입니다.
    //NULL: getopt_long()은 val의 값을 반환
    //NULL 이외: getopt_long()은 0을 반환하고 *flags에 val의 값을 대입
    
    int val;
    //옵션이 입력되었다면 여기에 지정한 값을 flag 변수에 대입
    //flag의 값에 따라 지정한 곳에 반환할 값
};

extern char *optarg;
extern int optind, opterr, optopt;
  • getopt()의 모든 기능을 포함하며 --로 시작하는 긴 옵션의 파싱도 가능하다.

  • 기본적 사용방법과 반환값이 같다.

  • 옵션 배열은 {0,0,0,0} 센티넬에 의해 만료된다

    구현 전략

    1. 짧은 옵션들을 먼저 정의한다.
    2. 긴 옵션명을 추가로 정의한다.
    3. 긴 옵션명 중에서 짧은 옵션명과 동일한 옵션인 것과 그렇지 않은 것을 구분한다.
    4. 짧은 옵션과 다른 긴 옵션의 경우 결과를 저장할 flag가 될 변수를 미리 준비한다.
    5. 1~4의 내용으로 옵션 구조체 배열을 정의한다. 이 배열은 {0, 0, 0, 0}의 센티넬로 마무리한다.
    6. getopt_long() 함수를 루프 속에서 처리한다.
    7. -1이 리턴될 때까지 반복한다
  • flags 멤버와 val 멤버는 함께 사용해야 하는데, 이 둘을 사용하는 방법에는 크게 두가지가 있다.

    • 1) flags에 NULL을 지정하고 val에 문자(char)을 지정하는 방법
    • ex) --help 옵션을 발견했을 때 getopt()가 'h'를 반환하게 하고 싶으면, flags를 NULL로 하고 val에 'h'를 대입한다. 그러면 결국 긴 옵션이 짧은 옵션에 대응되게 된다.
    • 2) boolean(1또는 0)의 의미를 가지는 int 타입 변수의 포인터를 flags에 지정하여 해당 옵션이 나타나면 val에 있는 값을 해당 포인터 변수에 지정하도록 하는 방법

https://github.com/Jpub/Linux_for_Everyone/blob/master/head4.c

getopt_long_only

getopt_long_only() : '-', '--' 모두 긴 이름 옵션으로 검색

memcpy(3)

void *memcpy(void *dest, const void *source, size_t num);

dest: 복사받을 메모리를 가리키는 포인터
source: 복사할 메모리를 가리키고 있는 포인터
num: 복사할 데이터(값)의 길이(바이트 단위)

  • source를 num만큼의 길이 만큼 복사해서 dest에 붙여넣는 함수
  • 주의1) 길이 계산할 때 char* 타입의 C언어 문자열 형태의 문자열의 전체를 복사할때는 맨 뒤에 문자열의 끝을 알리는 '\0'의 길이도 계산해서 넣어야하기 때문에 +1의 길이만큼 해주어야한다.
  • 주의2) memcpy는 source 메모리 블록과 dest 메모리 블록이 겹쳐져 있는 곳에서는 사용하지 못합니다. 즉 복사할 메모리랑, 복사한 결과값을 붙여넣을 메모리가 겹쳐져 있다면 함수가 제대로 작동하지 않습니다. 만약 동일한 메모리 공간에 덮어씌워야 한다면 memmove 함수를 사용하면 됩니다.

strcpy는 문자열 복사 함수로 길이지정을 안하는 대신 문자열이 반드시 \0로 끝나야합니다.(\0을 만나면 종료)
memcpy는 형에 관계없이 임의의 영역을 지정한 byte수만큼 복사(\0까지 처리하기 위해 size+1)



gdb

사전 조건

컴파일 시 -g 옵션을 주어야함

$ gcc -Wall -g -o head head.c

gdb 실행

$ gdb <프로그램명>
$ gdb <프로그램명> <core파일명>
$ gdb <프로그램명> <실행중인 프로세스 pid>

중단점 설정/확인/해제

  • break : 중단점을 설정한다.
break <함수이름>
break <라인번호>
break <파일이름:라인번호>
break <파일이름:함수이름>
break +<offset> // 현재 위치에서 오프셋 라인 뒤에 설정
break -<offset> // 현재 위치에서 오프셋 라인 뒤에 설정
break *address // 이미지의 주소 영역을 breakpoint로 설정
break <...> if <condition> // condition이 만족할때만 중단
  • info break : 중단점을 확인한다.
info break
info b
i b
>>>
Num     Type           Disp Enb Address    What
2       breakpoint     keep y   <PENDING>  a
3       breakpoint     keep y   <PENDING>  b
4       breakpoint     keep y   <PENDING>  c
  • clear : 중단점을 지정해 지운다.
clear <설정된 함수이름>
clear <설정된 라인번호>
clear <설정된 파일이름:라인번호>
clear <설정된 파일이름:함수이름>
  • delete : 중단점을 지운다.
delete // 설정된 모든 브레이크포인트를 지운다.
delete <breakpoint 번호> //번호에 해당하는 중단점을 지운다.
delete <breakpoint 번호> <breakpoint 번호> // 번호에 해당하는 중단점 모두 지운다.
  • disable / enable : 중단점을 활성화/비활성화한다.
en // 모든 중단점 활성화
enable // 모든 중단점 활성화
enable <중단점 번호> // 해당 중단점 활성화
enable <중단점 번호> <중단점 번호> // 해당 중단점 모두 활성화
dis // 모든 중단점 활성화
disable // 모든 중단점 활성화
disable <중단점 번호> // 해당 중단점 비활성화
disable <중단점 번호> <중단점 번호> // 해당 중단점 모두 비활성화

프로세스 실행

- run // 프로세스를 새로 실행, 이미 실행중이라면 재시작

- continue // 다음 중단점까지 프로그램을 재개
- conitnue n // 프로그램을 재개, 중단점을 n번 건너뜀

- next // 실행중인 프로세스를 한줄 실행, 함수 실행시 내부로 진입 X
- next n // 실행중인 프로세스를 n줄 실행, 함수 실행시 내부로 진입 X

- step // 실행중인 프로세스를 한줄 실행한다. 함수 실행시 내부로 진입
- step n // 실행중인 프로세스를 n줄 실행한다. 함수 실행시 내부로 진입

- finish // 현재 함수를 수행하고 빠져나간후 리턴값을 출력한다.

Call Stack 확인

backtrace : 현재 위치의 함수 call stack을 출력한다.

backtrace // 현재 실행 위치의 함수 call stack을 출력한다.
bt // 현재 실행 위치의 함수 call stack을 출력한다.
bt N // 현재 실행 위치의 함수 call stack 중 처음 N개 출력
bt -N // 현재 실행 위치의 함수 call stack 중 마지막 N개 출력
bt full // local 변수들도 함께 출력

값 출력/변경

  • print : 변수/주소 등을 출력한다
print <val> // 변수 출력
p <val> // 변수 출력
p <func::val> // 해당 함수의 변수를 출력한다.
p *<ptr> // 포인터의 값 
p <addr> // 주소에 있는 값
p arr[n] // arr 배열의 n번째 값 출력
p -pretty *<구조체> // 예쁘게 출력한다. 구조체를 출력할 때 용이하다.
p/x <val> // x(16진수) 형식으로 변수 출력
  • display : 매 실행(step, next, continue 등) 마다 출력한다.
display expr // 매 실행시 마다 출력한다.
display/fmt expr // 매 실행시 마다 fmt 포멧 형식으로 출력한다.

info dis // 설정된 display를 출력한다.
info display // 설정된 display를 출력한다.

enbale display // 모든 display를 활성화 시킨다.
en dis // 모든 display를 활성화 시킨다.
en dis <번호> <번호> // 번호에 해당하는 display를 활성화 시킨다.

disbale display // 모든 display를 비활성화 시킨다.
dis dis // 모든 display를 비활성화 시킨다.
dis dis <번호> <번호> // 번호에 해당하는 display를 비활성화 시킨다.
  • set : 변수/주소 등에 값을 할당한다.

기타

  • return : 현재 함수를 수행하지 않고 빠져나간다.
return // 현재 함수를 수행하지 않고 빠져나간다.
return -1 // 현재 함수를 수행하지 않고 빠져나간다. 리턴값은 -1
  • list : 소스 파일을 출력한다.
list // 현재 위치의 소스 출력 
list 100 // 100번째 라인 주변 소스 출력
list funtion // 지정 함수의 소스 출력  
list - // 직전에 출력한 소스 출력
set listsize count // 출력하는 라인수를 count로 설정한다.
set listsize unlimited // 출력하는 라인수 무제한

gdb core

  1. core dump파일 남기는지 확인
$ ulimit -a
//core file size          (blocks, -c) 0 이면 메모리 생성해야하므로  
$ ulimit -c unlimited
  1. file 명령으로 어느 파일의 core dump인지 확인
$ file core

  1. gdb를 사용하여 core 파일 분석
$ gdb tmsize core
  1. 이후
//콜스택 backtrace
$ bt

//frame 선택해서 스택 정보 보기
$ f 3

//해당 스택의 소스보기
$ list

//해당 스택의 argument 보기
$ info arg

//해당 스택의 local value 보기
$ info local

위와 같은 방식으로 코어 덤프 파일로부터 콜스택을 추적하여 프로그램이 비정상 종료된 원인을 찾아낸다.

0개의 댓글