php와 unsigned int

14 Jul, 2009  |  Written by codewiz  |  under 코드

예전에 한 땐 phper였고, phpschool을 제 집 드나들듯 했던 시절이 있었습니다. 여튼 나름 php는 왠만큼은 다룬다고 생각하고 살았습니다. 그런데, 그런데,… php를 알게 된지 근 10년이 다 된 오늘에서야 php가 무부호 정수 unsigned int를 지원하지 않는다는 사실을 알았습니다. 이건 뭥미… ㅠㅠ

예전부터 이상하게 로그를 받는 php 페이지에서 특정 로그 코드만 올라오지 않는 현상이 있었습니다. 0xe??????? 형태의 윈도우 오류 코드였습니다. 그 로그 코드는 너무 밑에서부터 위쪽 까지 여행을 하던 놈인데다, 특별히 중요한 코드도 아니어서 그냥 그간 무시하고 살았습니다. 그러다 오늘 그 프로그램 작업을 하면서 로그가 올라오지 않는 문제에 대해서 집중 분석을 하게 되었습니다.

단계별로 모두 찍었는데 잘못되는 구간은 없었습니다. 그런데 유독 최종 결과물 페이지에서만 이상하게 나오는 현상을 발견했습니다. 페이지를 디버깅 하기를 수차례 … 결국 php가 무부호 정수를 지원하지 않는 사실을 깨닫게 되었습니다.

물론 무부호 정수를 지원하지 않는다는 사실에는 그럴 수 있다고 생각합니다. 그런데 참으로 안타까운 디자인 상의 에러는 (물론 전적으로 제 생각입니다.) , intval 함수가 범위를 넘어서는 정수 값이 입력으로 들어오는 경우에는 INT_MAX를 반환한다는 사실입니다. 즉, php에서 다음 코드를 수행하면 “2147483647 7fffffff”라는 결과를 얻게 됩니다.

$arg = intval('3000000000');
printf("%u %08x", $arg, $arg);

 
자 인제 코드를 다음과 같이 변경해 보겠습니다. 그러면 정상적인 “3000000000 b2d05e00″라는 결과를 볼 수 있습니다.

$arg = intval(3000000000);
printf("%u %08x", $arg, $arg);

 
이 무슨 안드로메다 같은 현상입니까? ㅠㅠ~ 결국 다음과 같은 택도 아닌 함수를 만들어서 값을 보정하는 수 밖에는 없었습니다. 물론 라운딩 되는 숫자들이 수많은 프로그램 버그를 양산 해온건 사실이지만, 그래도 이건 쫌 그렇네용. ㅋㅋ~

function d2i($s)
{
 $r = 0;
 $len = strlen($s);
 for($i=0; $i<$len; ++$i)
 {
  $r = $r * 10 + intval($s[$i]);
 }
 return $r;
}

 
물론 여기에 좀 더 엘레강스한 해결책이 있을지도 모르겠네요.
아시는 분은 제보해 주세요. ㅎㅎ~

5 개의 댓글이 달렸습니다 댓글을 달아주세요.

트랙백 주소: http://jiniya.net/wp/archives/239/trackback
  1. 람다  |  July 15th, 2009 at 5:35 pm #

    PHP가 unsigned int를 지원 하지 안는데 궂이 3000000000이라는 숫자를 int라고 생각해야 하는 이유가 무엇인지요?

    PHP int의 범위를 벗어날 경우가 있는 경우라면 float으로 생각해야 하는게 맞는 것 같습니다만..

    $arg = floatval(3000000000);
    printf(“%u %08x”, $arg, $arg);

    람다 - Gravatar
  2. 람다  |  July 15th, 2009 at 5:46 pm #

    헛.. 댓글이 수정/삭제가 안되는군요…(제가 못 찾는건지..)

    윗 댓글에서 쓰고 싶었던 코드는
    $arg = floatval(’3000000000′);
    printf(”%u %08x”, $arg, $arg);

    입니다. (3000000000에 따옴표가 빠졌네요.)

    람다 - Gravatar
  3. 람다  |  July 15th, 2009 at 5:53 pm #

    $arg = d2i(’3000000000′);

    var_dump($arg);

    function d2i($s)
    {
    $r = 0;
    $len = strlen($s);
    for($i=0; $i<$len; ++$i)
    {
    $r = $r * 10 + intval($s[$i]);
    }
    return $r;
    }

    의 결과도 결국은..
    float(3000000000)

    그럼에도 불구하고 printf에 %u 옵션이 있는건 아이러니 하네요.

    $arg = intval(3000000000);
    var_dump($arg);

    를 해보면 결과는
    int(-1294967296) 입니다.

    아마 C의 printf 호환성을 위해 있는게 아닐까 짐작을 해봅니다.

    람다 - Gravatar
  4. codewiz  |  July 15th, 2009 at 8:51 pm #

    람다// 답글 잘 보았습니다. ㅎㅎ^^;;
    floatval을 쓰면 간단하게 해결할 수 있는 문제였군요.
    정수라고 생각한건 3000000000이 정수기 때문이죠.

    저도 댓글 수정 기능이 있는지 없는지, 어디 있는지 모르겠네용 ㅋㅋㅋ~
    좋은 댓글 감사합니다…

    codewiz - Gravatar
  5. 미니어스  |  February 5th, 2010 at 3:50 pm #

    미니어스 - Gravatar

피드백을 남겨주세요.

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>