21.3.1.2. `_main` 함수의 인자 전달 메커니즘

21.3.1.2. <module>_main 함수의 인자 전달 메커니즘

extern "C"의 가호를 받아 험난한 네임 맹글링을 피하고 NSH 심볼 테이블에 무사히 안착한 우리의 메인 함수는, 언제나 다음과 같은 똑같은 서명(Signature)을 가지고 있다.

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

괄호 안에 들어앉은 저 친숙한 두 개의 매개변수, argcargv[]는 C 프로그래밍을 갓 배운 학부생 시절부터 수없이 보아온 표준 커맨드라인 매개변수이다. 하지만 리눅스 데스크톱 환경과 픽스호크펌웨어 환경에서 이 변수들이 채워지는 과정은 하늘과 땅 차이만큼 다르다.

데스크톱 환경에서는 리눅스 커널과 bash 셸이 디스크에서 실행 파일을 읽어 올리면서 친절하게 파싱(Parsing)해 주지만, 픽스호크에서는 이 모든 문자열 토큰화 작업이 하나의 통렬한 펌웨어 메모리 내부에서, NSH(NuttShell)라는 초소형 커널 셸의 수작업을 통해 이루어지기 때문이다.

1. argcargv의 물리적 실체

  • argc (Argument Count): 사용자가 입력한 띄어쓰기로 구분된 문자열 단어(Token)들의 총 ’개수’를 나타내는 정수이다. 명령어 자기 자신(custom_app)도 첫 번째 단어로 포함하므로, 파라미터 없이 실행해도 argc는 무조건 최소 1이다.
  • argv (Argument Vector): 그 띄어쓰기로 구분된 단어 텍스트들의 시작 주소를 담고 있는 포인터 배열(Array of Pointers)이다.
  • argv[0] = "custom_app" (명령어 이름 자체)
  • argv[1] = "start" (첫 번째 파라미터)
  • argv[2] = "-p" (옵션 플래그)
  • 끝을 알리기 위해 배열의 맨 마지막 방에는 반드시 NULL 포인터가 들어간다.

2. NSH 콘솔에서의 입력 시나리오

비행장에 나간 여러분이 노트북으로 QGroundControl에 접속하여 MAVLink Console(가상 NSH 터미널) 창을 열었다. 그리고 키보드로 다음과 같이 타이핑하고 엔터(Enter) 키를 내리쳤다.

nsh> custom_app start -i 5 -f

이 텍스트 한 줄이 텔레메트리 무선 통신을 타고 드론의 픽스호크 USB 칩을 거쳐 CPU로 꽂히면, NuttX 커널은 이 긴 문자열을 통째로 받아든다.

커널은 이 텍스트를 그냥 여러분의 메인 함수에 덩끄러니 던져주지 않는다. 만약 그랬다면 여러분은 custom_app_main 첫 줄부터 strcmp나 정규표현식(Regex)을 돌리느라 밤을 새워야 했을 것이다. 대신, NSH 내부 파서(Parser)가 start, -i, 5, -f라는 글자 뭉치들을 스페이스바(공백)를 기준으로 정교하게 쪼개고(Tokenizing), 널(Null, \0) 문자로 마무리하여 안전한 C 스타일 문자열의 배열 argv로 예쁘게 포장해 준다.

그렇게 포장된 박스가 다음과 같이 custom_app_main의 품에 안긴다.

  • argc = 5
  • argv[0] = "custom_app", argv[1] = "start", argv[2] = "-i", argv[3] = "5", argv[4] = "-f", argv[5] = NULL

그렇다면 구체적으로 저 긴 통문자열이 픽스호크 램 공간 안에서 어떤 식으로 분해되고 포인터 배열로 묶이는지, NuttX의 텍스트 처리 속살을 다음 단원(21.3.1.2.1)에서 낱낱이 파헤쳐보겠다.