기본 콘텐츠로 건너뛰기

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이 복제를 안 하고, 앞에 인자를 그대로 넘겨주면 대박)

댓글

이 블로그의 인기 게시물

Bash Array, Map 정리

Bash에서 Array, Map에 대한 정리. (매번 찾기 귀찮) 찾아보진 않았지만, Bash에서 Array든 Map이든 동일하게 Map(C++에서 Unordered Map)으로 동작하는 것 같다. 왜냐하면, Array의 Index가 연속하지 않아도 동작한다. 그저 Key가 0 이상의 정수인 Map이랑 비슷하게 동작한다. 예) 1, 2, 3, 9, 10 Array # 생성 declare -a empty_array declare -a ar=(haha hoho baba "long string haha hoho") # 접근 echo "ar[0]=${ar[0]}" echo "all as array=${ar[@]}" # 큰따옴표 안에서 각 원소를 따로따로 전달한다. echo "all as one=${ar[*]}" # 큰따옴표 안에서 각 원소를 문자열 하나로 합쳐 전달한다. echo "indexes=${!ar[@]}" echo "indexes=${!ar[*]}" echo "length=${#ar[@]}" echo "length=${#ar[*]}" echo "last=${ar[-1]}" echo "last=${ar[@]: -1}" # 콜론 뒤에 빈 칸이 꼭 필요하다. 옛 방식 # 현재 상황 declare -p ar #(출력) declare -a ar=([0]="haha" [1]="hoho" [2]="baba" [3]="long string haha hoho") ar[100]=hello # 인덱스를 건너 뛰어도 동작한다. declare -p ar #(출력) declare -a ar=([0]="haha" [1]="hoho" [2]="baba" [3]=&

설치한 패키지에서 RPM 추출하기

오래된 패키지를 관리할 저장소가 없어졌고, 기존 패키지로 다른 서버를 세팅해야할 일이 생겼다면 RPM의 리패키지 기능을 이용해보자. $ rpm -e --repackage [PACKAGE_NAME] 위와 같이 리패키지하면, /var/spool/repackage/ 에 생성한 RPM파일이 있다. :-)