나는 엔진 코드에서 가변함수 scanf,fscanf등의 함수를 진짜로 가변적으로 호출하곤 했다. 예를 들면 스크립트를 파싱해서 2개의 문자열을 읽을지, 3개의 문자열을 읽을지를 결정해야한고 치자.
코드는 이런식이다.
fscanf(fp,”%s %s”,buf0,buf1); // 2개를 읽을 경우
fscanf(fp,”%s %s %s”,buf0,buf1,buf2); // 3개를 읽을 경우
이걸 n개의 문자열을 읽는다고 치면? 모든 n개의 케이스에 대해서 fscanf(문을 일일히 다 만들어놓을순 없지 않은가?
“%s “부분은 가변적으로 문자열을 만들어서 넣어줄수 있다. 문제는 뒤에 문자열 버퍼의 포인터를 전달하는 부분이다.
가변인자 함수를 호출할때는 내부적으로 인자를 전달하는게 아니고 인자들이 연속으로 저장되어있는 메모리의 포인터를 전달한다. vfscanf()등도 그렇게 작동한다.
Windows의 경우 vfscanf()는 시스템 내부에서만 사용하고 프로그래머는 사용할 수 없다.
MSDN을 열심히 뒤져보니 posix에선 표준이지만 윈도우에선 지원하지 않는다는 내용을 찾아볼 수 있었다.
그래서 이런 역할을 해주는 코드를 32비트 인라인 어셈블리어로 작성해서 사용했었다. 32비트에선 인자를 스택으로 전달하므로 쉽다.
32비트 어셈코드는 잘 작동했지만 2007년에 엔진을 64비트로 포팅하면서 문제가 생겼다.
- x64타겟일때 Visual Studio는 인라인 어셈블리를 지원하지 않는다.
- x64의 calling convention은 기본적으로 fastcall이고 x86보다 복잡하다.
그래서 2007년도에 x86/x64에서 사용할 수 있는 가변인자 전달 코드를 작성했다. 꼭 fscanf에만 적용되는것은 아니고 그런 스타일의 함수에는 모두 적용할 수 있다.
예제에서는 가변인자의 개수와 가변인자의 배열의 포인터를 넣어서 fscanf를 호출하고 있다.
2007년에 Visual Studio 2005 기준으로 작성했던 샘플 프로젝트인데 Visual Studio 2015에서 빌드되도록 좀 수정했다.
소스코드는 github에 올려놓았다.
https://github.com/megayuchi/win32/tree/master/fscanf_call
아래는 2007년도 당시 작성했던 게시물. 예전 yuchi.net에 있던 게시물을 긁어다가 워드프레스로 옮겨놓았다.