2009년 11월 24일 화요일

PHP RETURN_STRINGL 까보기

요즘 이것저것 많이 건드는군... 오늘은 일부 라이브러리를 PHP extension으로 포팅할 일이 있어서 CentOS 5.4에서 php-devel이란 패키지를 깔고 깔짝거리고 있다. 상당 수 매크로 함수로 칠해놓은 API를 통해 PHP extension으로 포팅해야는데, 다른 거야 뭐 그럭저럭 하는데, std::string::c_str()을 RETURN_STRINGL 매크로 함수로 반환하려고 했더니 마이클잭슨 같은 경우가 발생했다.

error: invalid conversion from ‘const char*’ to ‘char*’

이게 뭐신가 하면... RETURN_STRINGL 첫번째 인자가 char*인가부다. 근데 std::string::c_str()은 const char*이란 말이지. 일단 RETURN_STRINGL이 어떻게 생겨먹은 놈인지 확인하러 휘리릭 뽕 퓨젼~

일단 RETURN_STRINGL은 /usr/include/php/Zend/zend_API.h에 있다.

#define ZVAL_STRINGL(z, s, l, duplicate) {  \
        char *__s=(s); int __l=l;       \
        (z)->value.str.len = __l;       \
        (z)->value.str.val = (duplicate?estrndup(__s, __l):__s);    \
        (z)->type = IS_STRING;          \
    }

#define RETVAL_STRINGL(s, l, duplicate)     ZVAL_STRINGL(return_value, s, l, duplicate)

#define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; }

음... 매크로 함수가 매크로 함수를 부르고 그게 또 매크로 함수를 부르고... 아웅... 포기할까... orz
일단 RETURN_STRINGL은 RETVAL_STRINGL을 호출한다. 이때 갑툭튀 return_value라는 걸, ZVAL_STRINGL에 넘겨준다. 아마 함수를 선언하는 PHP_FUNCTION 매크로 함수에 return_value라는 녀석이 있을 것이다.

PHP_FUNCTION을 찾아보니, ZEND_FUNCTION 매크로 함수의 다른 이름이고, ZEND_FUNCTION은 zif_를 함수명 앞에 붙여, 결국 void zif_함수명(INTERNAL_FUNCTION_PARAMETERS)라는 구문을 만들어준다. 어라? return_value를 선언해주는게 없는디? 귀신에 홀렸나... = _= 이 부분은 나중에 다시 써야겠다.

중요한 것은 ZVAL_STRINGL에서 넘겨 받은 문자열을 char* __s로 받고 있기 때문에 컴파일 타임에 오류가 난 것이다. duplicate값이 1이면 그냥 const char*로 받아도 될 것 같은데 아쉽고만...

이러면 안 되지만... duplicate값이 1이면 그냥 const_cast로 const를 떼고 넘겨줘도 무방할 것 같다. 결국 estrndup를 호출하고, 입력값 상태와 상관 없이 새로 할당해서 복제한 문자열 포인터를 얻을 수 있을테니까. (이랬는데 estrndup이 복제를 안 하고, 앞에 인자를 그대로 넘겨주면 대박)