본문으로 바로가기

C언어에서 Tcl의 변수를 세팅 그리고 변수의 값을 다시 C언어에서 얻는 방법에 대해서 알아볼 것입니다.

예제

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <tcl.h> // (1)
 
static void application(Tcl_Interp* interp, char* myname);
 
int main(int argc, char *argv[])
{
        Tcl_Interp *interp;
        char *myname ="inhak";
 
        interp = Tcl_CreateInterp(); // (2)
        Tcl_FindExecutable(argv[0]); // (3)
        if(Tcl_Init(interp) == TCL_ERROR) { // (4)
                fprintf(stderr, "Tcl interpreter initialization failed.\n");
                return  1;
        }
        application(interp, myname);
        Tcl_DeleteInterp(interp);
        return  0;
}
 
static void
application(Tcl_Interp *interp, char *myname )
{
        char *p;
        char buf[256];
 
        Tcl_SetVar(interp, "name", myname ,0); // (5)
        strcpy(buf, "set msg \"Hello, World and $name\""); // (6)
        if(Tcl_Eval(interp, buf) == TCL_ERROR) {
                fprintf(stderr, "Interpretaion error:%s\n",
                    Tcl_GetStringResult(interp)); // (7)
                return;
        }
        if((p = Tcl_GetVar(interp, "msg" ,0)) != NULL) // (8)
        fprintf(stderr, "<%s>\n", p);
}

Borland C++

bcc32 -IC:\tcl\include -LC:\tcl\lib demo.c tcl84bcc.lib

Visual C++

cl /I "C:\tcl\include" demo.c C:\tcl\lib\tcl84.lib

(1) Tcl API를 사용하기 위해 필요한 헤더 파일인 tcl.h를 include합니다. 또한 Tk의 API를 사용하기 위해서는 tk.h를 include 해야 합니다.

(2) Tcl_CreateInterp를 호출하여 Tcl_Interp 형태의 변수 포인터를 얻습니다. 커맨드의 해석 및 실행시에는 이 변수가 필요하게 되며, 이 변수가 Tcl 인터프리터가 됩니다. Tcl_Interp형의 포인터 변수의 이름은 보통 interp로 통일하고 있습니다. (많은 확장의 패키지 소스도 이 이름을 준수하고 있습니다.) 보통 interp는 한 번만 만들면 됩니다. Tcl 인터프리터가 필요 없어지면 Tcl_DeleteInterp를 호출하여 메모리에서 제거합니다.

(3) Tcl_FindExecutable은 8.1b2 이후의 버전에서 추가된 것으로 Tcl_Init를 부르기 전에 반드시 호출할 필요는 없습니다. 단, 이전의 버전에는 쓰이지 않습니다.

(4) Tcl_Init는 초기에 부릅니다. Tcl_Init는 인터프리터에 빠짐없이 따라오는 스크립트인 init.tcl을 source 하고 있는것 뿐, init.tcl에 정의되어 있는 procedure나 변수가 현재 자신의 애플리케이션에서 사용되지 않는 것이 명확하다면 반드시 호출할 필요는 없습니다. Tk 커맨드를 사용할 경우는 Tk_Init를 호출하며, Tk 커맨드를 사용할 때는 반드시 Tk_Init API를 호출해야 합니다.

(5) Tcl_SetVar는 그 Tcl 인터프리터내의 Tcl 변수의 값을 세팅하는 일반적인 API입니다. 이 API는 변수를 세팅하는 API로 바이너리 데이터는 세팅을 할 수 없습니다. 바이너리 데이터를 Tcl의 변수에 세팅하기 위해서는 Tcl_SetVar2Ex라고 하는 API를 사용하면 됩니다.

(6) Tcl_Eval은 Tcl API의 수 많은 함수중 가장 일반적인 API이며, 문자열로 지정한 Tcl커맨드를 해석하는 기능을 합니다. 이 API는 Tcl의 커맨드를 정상적으로 수행하게 되면, TCL_OK를 리턴하며, 에러가 발생하면 TCL_ERROR를 리턴합니다. 주의할 점은 두 번째 인자로 지정하는 Tcl커맨드의 문자열은 아래와 같이 반드시 문자열 영역을 지정해야 합니다.

Tcl_Eval(interp, "puts {Hello, World}");

(7) Tcl_Eval을 사용한 후 Tcl_GetStringResult로 실행한 커맨드의 결과를 얻어올수 있습니다. 정상 종료일 경우는 커맨드를 실행한 결과의 값이 나오고, 실패한 경우는 에러 메시지를 문자열로 얻을 수 있습니다. 이 API는 바이너리 데이터는 받을 수 없으며, 바이너리 데이터를 얻기 위해서는 Tcl_GetObjResult라고 하는 API를 사용해야 합니다.

(8) Tcl_GetVar은 Tcl의 변수를 얻어내는 일반적인 API입니다. 값은 문자열로 리턴되며, 만약 존재하지 않는 변수이면 NULL이 나오게됩니다. 이 API는 변수의 값에 바이너리 데이터가 있으면 변수를 얻어올 수가 없습니다. 바이너리 데이터를 Tcl의 변수로부터 얻고 싶으시다면, Tcl_GetVar2Ex를 사용합니다.

Tcl_EvalEx에 대하여

Tcl_EvalEx는 Tcl_Eval과 같이 커맨드를 해석하여 실행하지만,

Tcl_EvalEx(interp, command, -1, TCL_EVAL_GLOBAL);

위에서와 같이 네번째 인자에 TCL_EVAL_GLOBAL을 지정하면, 글로벌 영역의 커맨드를 해석 및 실행을 할 수 있습니다.

세 번째 인자는 보통 strlen(command)와 같이 커맨드 문자열의 길이를 지정하지만, -1을 지정하게 되면 자동적으로 문자열의 길이 계산해 줍니다. 또한 Tcl_EvalEx가 Tcl_Eval보다 처리속도가 빠릅니다. 그 외에 Tcl_EvalFile API는 Tcl 언어의 스크립트 파일을

Tcl_EvalFile(interp, filename);

 

위와 같이 지정하면, 주어진 filename의 소스 전체를 해석및 실행하고, 정상적으로 실행이 됐으면 TCL_OK, 에러가 발생하면 TCL_ERROR를 돌려줍니다. Tcl_EvalEx는 Tcl8.0 이후부터 사용가능합니다.

다른 예제

다음 예제는 더욱 간단한 프로그램 입니다. 이것으로 Tcl_Eval과 Tcl_GetStringResult를 이해할 수 있으면 합니다.

#include <stdio.h>
#include <tcl.h>
 
int
main(int argc, char *argv[])
{
        char command [1024];
        Tcl_Interp *interp;
 
        if(argc != 3) {
                fprintf(stderr, "usage:%s num1 num2\n", argv[0]);
                return  1;
        }
        interp = Tcl_CreateInterp();
        sprintf(command, "expr %s*%s\n", argv[1], argv[2]);
        if(Tcl_Eval(interp, command)== TCL_ERROR) {
                fprintf(stderr, "ERROR:%s\n", Tcl_GetStringResult(interp));
        } else  {
                fprintf(stdout, "%s\n", Tcl_GetStringResult(interp));
        }
        return  0;
}

Borland C++

bcc32 -IC:\tcl\include -LC:\tcl\lib demo.c tcl84bcc.lib

Visual C++

cl /I “C:\tcl\include” demo.c C:\tcl\lib\tcl84.lib