Help us understand the problem. What is going on with this article?

PHP5で16進数を符号付10進数に変換する方法(4byte)

経緯

仕事でPHPで0xから始まる16進数を符号付きの10進数に変換する必要があったが、ネットで探してもなかなか見つからなかったため備忘録として記載。

結論

    //16進数を符号付き10進数に変換する
    private function hex_to_decimal($val)
    {
        //0x表記の場合
        if (strpos($val,"0x") === 0) {
            //「0x」の箇所を削除する
            $hex = substr($val,2);
        }

        //先頭文字の1ビット目が1→マイナス
        if (hexdec(substr($hex,0,1)) & 8 && strlen($hex) === 8) {
            //2の補数で絶対値を取得
            $hex = (hexdec($hex) ^ (16 ** strlen($hex)-1)) + 1;
            //マイナスに変換
            $dec = 0 - $hex;
        } else {
            //先頭文字の1ビット目が0→プラス
            $dec = hexdec($hex);
        }
        return $dec;
    }

解説

符号付16進数はビット列の最初の値で正負の判断をしている。
・先頭ビットが1→負
・先頭ビットが0→正
例として負の値-1(16進数:0xFFFFFFFF)で解説。

まずは、下記の箇所

    if (hexdec(substr($hex,0,1)) & 8) {

hexdec(substr($hex,0,1))で16進数の最初の文字「F」の10進数(=15)を取得。
15(2進数で1111)と8(2進数で1000)のビット積を求めることで、最初のビットが1か0かを判定することができる。(&はビット積の意)
最初のビットが1の場合は負の値のため、下記の処理に移る。

    $hex = (hexdec($hex) ^ (16 ** strlen($hex)-1)) + 1;

ここでは元の16進数(0xFFFFFFFF)と32ビット分全て"1"の数値を排他的論理和でビット演算を行い、その数値にプラス1をすることで2の補数で負の値の絶対値を取得している。

その後に、下記の計算で負の値に変換して終了。

    $dec = 0 - $hex;

最後に

もっといい方法あったら教えてください!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away