OS

[OS] C언어 코드 분석_2

효진인데요 2023. 12. 11. 13:59

 

 

작년, 그러니까 3학년 2학기에 운영체제 강의를 들으며 주어졌던 C code 분석 과제를 다시 한번 정리해보려고 한다.

 

C 언어로 작성된 코드를 주고 이를 분석하는 과제였는데, C 언어를 한 번도 사용해 본 적 없을 때라 (사실 현재까지도) 어려웠지만 흥미로웠던 기억이 있었다.

 

C 언어를 배우기 전이기도 하고, 구조에 대해 이해하고 코드를 분석해 보는 데에 의의를 둔 것이기에,

분석하고 정리한 내용이 정확하지 않을 수도 있는 점,,🙏🏻

 

https://jinnycoding.tistory.com/76

 

[OS] 자료구조(연결 리스트, 스택), include문과 포인터 변수

작년, 그러니까 3학년 2학기에 운영체제 강의를 들으며 주어졌던 C code 분석 과제를 다시 한번 정리해보려고 한다. C 언어로 작성 된 코드를 주고 이를 분석하는 과제였는데, C 언어를 한 번도 사

jinnycoding.tistory.com

 

 

위 포스팅이 1탄이고 이번 포스팅에는 본격적인 코드 분석이 주 내용이 될 것 같다.

 

 

나도 이해하기 쉽도록 대부분 주석으로 간단하게 설명을 적어가며 최대한 정확하게 분석하려고 노력 많이 했었다...^^

 

 

 

 

1.   main 함수

  



  • argc : 메인 함수에 전달되는 정보의 개수 (argument count)
  • argv : 메인 함수로 전달되는 실질적인 정보
  • argv[0]에는 실행 파일 명, argv [1], [2], … 에는 사용자가 입력한 argument가 저장한다.

 

main 함수 안 변수 중 char 형 line, dummy, lineyedek, postfix는 표준 입력 시스템의 특성을 활용하여 입력을 받도록 했다.

표준 입력 버퍼의 길이는 일반적으로 4096으로 제한되어 있기 때문에 [4096]을 변수 이름 뒤에 붙여서 이 이상의 길이를 가진 문자열에 대해 제한을 두었다.

 

int형 변수 val1과 val2, LastExpReturn, CalingRunctionArgVal, resultVal을 생성한다.

이때 int형 변수 LastFunctionReturn에는 -999라는 값을 넣는다.

 

앞서 만들어 두었던 Node 연결 리스트를 tempNode라는 변수에 지정하고 OpStack의 주소 값을 MathStack에, 처리할 FILE을 가리키는 FILE 포인터는 filePtr으로, PostfixStack의 주소 값은 CalcStack에 넣는다.

 

Stack의 주소 값을 STACK에 저장하고 int형 변수 curline과 foundMain, WillBreak를 생성하고 모두 0으로 설정한다.

MathStack, CalcStack, STACK 스택 내부에 데이터가 아직 없으므로, top 포인터는 NULL 값을 가진다.

 

함수 clrscr은 화면을 초기화하는 함수이다.

 

 

 

 

 

 

파일을 열 수 없는 경우를 대비한 if문이 두 가지가 설정되어있다.

 

먼저 인자 1개를 받기를 원하는 경우, 실행 파일도 하나의 인자이기 때문에 포함해서 2가 되어야 한다.

이 경우를 걸러내기 위한 if문이다. argc의 개수가 2가 아닌 경우, if문으로 진입해 argument의 파일 이름을 출력하고 1을 반환한다.

 

두 번째 조건을 보면 fopen함수를 이용하여 argv [1]의 파일을 read mode로 열려고 하는데, 이 값이 NULL이면 if문이 참이 되어 내부로 접근이 가능하다.

파일을 열 수 없으니 확인해 달라는 에러 메시지를 출력한 뒤 2를 반환한다.

 

C언어에서 main 함수 내의 return 값을 보면, 0인 경우 에러가 없이 정상적으로 프로그램이 종료되었음을 의미하고, 0이 아닌 다른 숫자의 경우 에러가 발생했음을 알린다.

 

위 두 if문은 에러를 대비한 코드이기 때문에 0을 반환하지 않는다.

 

 

 

 

 

 

위 코드에서 나오는 함수들을 먼저 확인해 보기로 했다.

 

 

1.1 feof 함수

 

 

 

feof 함수 원형

 

 

 

feof 함수는 파일의 끝인지 알려주는 함수로, !feof(filePtr)을 조건으로 반복문을 돌리면 이는 파일의 끝을 만날 때까지 루프를 도는 것을 의미한다.

이때, 파일 포인터가 끝을 가리켜도 함수는 한 번 더 실행이 되고, 거기서 에러가 나와야 true가 되어 반복문을 탈출한다.

반환 값의 경우 0이면 파일이 끝나지 않았다는 것을 의미하고 0이 아니면 True상태가 되어 파일이 끝났음을 알린다.

 

 

 

1.2   fgets 함수

 

 

fgets 함수 원형

 

 

fgets 함수는 아래 사진과 같이 3개의 인자를 받는다.

 

 

 

 

1.3  strcpy 함수

 

strcpy 함수 원형

 

 

strcpy 함수란 string copy, 즉 문자열을 복사하겠다는 함수이다.

 

위 원형 함수 같은 경우 origindest로 복사하겠다는 것을 의미한다.

 

 

 

 

위 코드를 해석해 보자면 filePtr 파일을 line 별로 읽어올 것이며, 읽어 들일 수 있는 최대 문자 수는 마지막의 NULL 값을 포함하여 총 4096개임을 확인할 수 있다.

 

  1. 다음 나오는 while문은 int k를 1씩 증가시키며 line 배열에 저장한다. 이때 문자열이 \0이 아니면 반복문을 돌다가, \t를 만났을 경우 공백으로 덮어씌우고 k에 1씩 더해가며 문자열 검사를 진행한다. 이 과정은 \t를 먼저 없애 파일 중간에 존재할 수 있는 큰 공백을 먼저 제거하기 위함이다.

  2. 앞서 \t를 지운 문자열이 다 돌고 반복문을 빠져나오면 line 문자열을 lineyedek에 복사한다.

  3. curline 0인 상태에서 feof while문이 돌 때마다++을 하며, tempNode의 데이터 값들 중 int형은 모두 -999로 그리고 char형은 공백으로 값을 전환한다.

 

 


 

 

 

 

 

다음으로 나오는 함수는 첫 번째로 문자열 검사를 진행할 if문이다. 우선 strcmpi 함수의 특징은 아래 그림과 같이 볼 수 있다.

 

 

1.4 strcmpi 함수

 

strcmpi 함수 원형

 

 

 

strcmpi 함수는 대소문자를 구분하지 않고 문자열을 비교한다.

비교를 시작하기 전 모두 소문자로 변환된 상태로 비교가 진행되며, 함수는 NUL로 끝나는 string에서 작동을 한다.

 

, 이 안에 들어가는 인수는 끝을 나타내는 NUL(\0) 문자를 포함한 상태라고 할 수 있다.

 

 

  1. If문의 조건문은 참이 되어야 내부 코드로 들어갈 수 있기 때문에 반환되는 값이 0이 아닌 다른 값이어야 한다.
    해당 조건문을 보면 strcmpi 함수 두 개가 \ 연산자(or)로 묶여 있는 것을 확인할 수 있는데, 이때 앞서 봤던 것과 같이 string1과 string2가 같으면 0이 반환되기 때문에 조건문에 들어갈 수 있는 1을 반환하기 위해 !(not)연산자를 붙여주었다.

    결과적으로 해당 코드를 해석해 보면 line이 begin, 혹은 begin\n과 동일하면 if문을 수행하라는 의미이다.

  2.  내부 코드를 보면 int형 변수 foundMain이 현재 0으로 설정되어 있는 상태인데, tempNode type 데이터를 4로 변환하여 STACK Push하라는 의미이다.

 

 

 


 

 

 

아주... 정신없이 나눠뒀군..... 왜 그랬니 과거의 나

 

 

두 번째 else if문을 보기 전 사용되는 함수들을 먼저 분석해보려고 한다.

 

 

 

2.1 GetLastFunctionCall 함수

 

GetLastFunctionCall 함수

 

 

 

우선 Stack 스택을 stck이라는 포인터로, Node 연결 리스트는 head라는 포인터로 주소를 알려주는 변수를 만든다.

만약 stck의 최상단이 NULL인 상태이면 빈 스택이라 오류가 나고, 에러 메시지를 띄운 뒤, if문을 빠져나와 가장 하단 return문으로 가서 0을 리턴하고 함수가 종료된다,

 

스택이 빈 상태가 아닌 경우, head는 스택의 top을 가리키고, do-while문을 돈다. head의 타입이 3이면 해당 head line을 리턴하고 함수를 빠져나온다.

headtype이 아닌 경우, 다음 노드를 가리키고 계속해서 while문을 돈다. 마지막 요소가 NULL이 아닌 경우 돌고, NULL을 만나면 함수에서 빠져나오고 0을 리턴한다.

 

 

 

2.2 Push 함수

Push 함수

 

Push 함수는 Node newnode라는 포인터 변수에 저장한다.

newnode Node 타입의 사이즈만큼의 메모리 할당이 안되면 메모리 할당에 실패했다는 오류 메시지와 함께 함수를 빠져나간다.

할당이 성공할 경우, newnode의 데이터들은 sNode의 데이터 값들로 설정된다.

 

 

 

2.3 Pop 함수

Pop 함수

 

다음으로 Pop 함수이다. 해당 함수는 리턴 값이 존재하지 않는다.

Node sNode, Stack stck를 포인트 하며 Node형 자료를 temp라는 변수에 주소를 저장한다.

 

만약 stck 스택의 topNULL 상태이면 빈 스택이라는 오류 메시지를 띄운다.

 

빈 스택이 아니면 sNode exp_data, type, line, val은 차례로 stcktop에 있던 exp_data, type, line, val을 가리키며 tempstcktop을 가리키도록 변경된다.

stcktop은 그다음을 가리키도록 하고, 마지막에 임시로 값을 가리키고 있던 temp 변수에 할당되었던 메모리의 공간을 해제한다.

 

 

 

 

 

전체 코드로 돌아가 두 번째 문자열 검사를 진행할 함수는 위와 동일한 형태로 strcmpi 함수를 사용하였고, lineend 혹은 end\n이 동일할 경우 내부 빨간색 범위 코드로 진입할 수 있게 된다.

이때, int형 변수 sline을 생성하고, tempNode type5로 설정한 상태로 STACK에 Push 하도록 한다.

 

 

  1. GetLastFunctionCall 함수에 STACK을 넣고 리턴 값을 sline에 넣는다.

  2. 만약 sline 0이면 LastExpReturn값을 넣어 출력한다.

  3. sline의 값이 0이 아닌 경우, 정수형 변수 j foundcall을 생성한 뒤 LastExpReturn 값을 LastFunctionReturn 값에 대입한다. fclose 함수를 사용하여 filePtr파일을 종료한 뒤, 다시 파일을 열고 curline 0으로 설정하여 파일 시작 위치로 이동한다.
  4. 그 뒤 for문을 도는데, 조건문을 보면 j = 1이고 1씩 더해가며 파일을 끝까지 돌도록 함을 알 수 있다. filePtr 파일을 가져와 char dummy를 읽어 들인다.
  5. for문이 종료되면 while문으로 내려와 foundCall의 값이 0이면 하나씩 Pop하고, 만약 tempNode의 타입이 3이 되면 foundCall의 상태를 1로 바꾸고 종료한다.
728x90