記事内にはプロモーションが含まれています

【C言語】16進数と10進数を相互に変換する方法!strtolやsprintfの使い方

【C言語】16進数と10進数を相互に変換する方法!strtolやsprintfの使い方 C言語

C言語でプログラミングを行っていると、メモリのアドレス計算や色コードの処理、バイナリデータの解析などで「16進数」と「10進数」を相互に変換したい場面によく遭遇します。

しかし、一言で「変換」と言っても、「16進数の文字列を10進数の数値にしたいのか」、それとも「数値を16進数形式の文字列として保存したいのか」、あるいは「単に画面に16進数で表示したいだけなのか」によって、使用すべき関数や手法は異なります。

この記事では、C言語における16進数と10進数の変換について、標準ライブラリ関数である strtolsprintf を使った最も一般的で安全な実装方法を、具体的なサンプルコード付きで解説します。

【本記事の信頼性】
プロフィール
執筆者:マヒロ
  • 執筆者は元エンジニア
  • SES⇒大手の社内SE⇒独立
  • 現在はこじんまりとしたプログラミングスクールを運営
  • モットーは「利他の精神」

C言語における16進数と10進数の扱いについて

まず大前提として、コンピュータ内部では数値はすべて「2進数」で扱われています。
C言語の int 型などの変数に入っている値自体には、10進数や16進数といった区別はありません。

一般的に「変換」と呼ばれているのは、主に以下の2つの操作を指します。

  1. 文字列から数値への変換"1A""0xFF" といった文字の並びを、計算可能な数値データ(整数)に変換すること。
  2. 数値から文字列(または表示)への変換:変数に入っている数値を、人間が読める "1A" のような形式の文字データとして出力すること。

この違いを意識しながら、それぞれの実装方法を見ていきましょう。

16進数文字列を10進数(数値)に変換する strtol

文字列として表現された16進数(例: "FF""0x10")を、int 型などの数値に変換するには、標準ライブラリの stdlib.h に含まれる strtol 関数 を使用するのがベストプラクティスです。

似た関数に atoi がありますが、atoi は16進数に対応しておらず、エラー処理もできないため推奨されません。

strtol 関数の基本的な使い方

strtol(string to long)は、文字列を long 型の整数に変換する関数です。
第3引数に基数(何進数か)を指定できるため、ここで 16 を指定することで16進数文字列を解析できます。

#include <stdio.h>
#include <stdlib.h> // strtolを使うために必要

int main(void) {
    // 変換したい16進数の文字列
    const char *hexStr1 = "1A";
    const char *hexStr2 = "0xFF";
    const char *hexStr3 = "100";

    char *endptr; // 変換できなかった文字へのポインタを格納する

    // strtol(文字列, 終端ポインタ, 基数)
    long num1 = strtol(hexStr1, &endptr, 16);
    long num2 = strtol(hexStr2, &endptr, 16);
    long num3 = strtol(hexStr3, &endptr, 16);

    printf("文字列: %s -> 10進数: %ld\n", hexStr1, num1);
    printf("文字列: %s -> 10進数: %ld\n", hexStr2, num2);
    printf("文字列: %s -> 10進数: %ld\n", hexStr3, num3);

    return 0;
}

実行結果

文字列: 1A -> 10進数: 26
文字列: 0xFF -> 10進数: 255
文字列: 100 -> 10進数: 256

ソースコードの解説

  • #include <stdlib.h>strtol 関数を使用するために必要なヘッダファイルです。
  • strtol(hexStr1, &endptr, 16):第1引数に変換元の文字列、第2引数に変換終了位置を格納するポインタのアドレス、第3引数に基数 16 を指定します。
  • 基数の指定16 を指定することで、"A" は10、"F" は15として計算されます。また、"0x" という接頭辞が付いていても自動的に認識して無視してくれるため、非常に便利です。

エラー処理を含めた堅牢な実装

実務では、渡された文字列が「正しい16進数ではない」場合に備える必要があります。

strtol の第2引数を利用することで、正しく変換できたかどうかをチェックできます。

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *invalidHex = "1G5"; // 'G'は16進数ではない
    char *endptr;

    long num = strtol(invalidHex, &endptr, 16);

    // *endptr が '\0'(終端文字)でない場合、変換できなかった文字がある
    if (*endptr != '\0') {
        printf("エラー: '%s' は正しい16進数ではありません。\n", invalidHex);
        printf("変換できた部分: %ld, 無効な文字: %c\n", num, *endptr);
    } else {
        printf("変換成功: %ld\n", num);
    }

    return 0;
}

実行結果

エラー: '1G5' は正しい16進数ではありません。
変換できた部分: 1, 無効な文字: G

ソースコードの解説

  • *endptr != '\0':変換処理は、16進数として解釈できない文字(この場合は ‘G’)に出会った時点で停止します。文字列の最後まで到達していなければ、不正な文字が含まれていたと判断できます。
  • このチェックを入れることで、予期せぬ入力によるバグを防ぐことができます。

10進数(数値)を16進数文字列に変換する sprintf

逆に、計算結果などの数値を「16進数の文字列」として保存・利用したい場合は、stdio.h に含まれる sprintf 関数(または安全な snprintf)を使用します。

sprintf で数値を16進数文字列にする

printf が画面に出力するのに対し、sprintf は配列(バッファ)に出力します。

ここで変換指定子 %x または %X を使います。

#include <stdio.h>

int main(void) {
    int decimalNum = 255;
    char hexBuffer[20]; // 結果を格納する配列(十分なサイズを確保する)

    // %x は小文字(a-f)、%X は大文字(A-F)で出力
    sprintf(hexBuffer, "%X", decimalNum);

    printf("10進数: %d -> 16進数文字列: %s\n", decimalNum, hexBuffer);

    // 0埋めや0xを付けたい場合
    // %04x -> 4桁になるように0埋め
    // %#x  -> 0xを付与
    sprintf(hexBuffer, "%#06x", decimalNum); // 0x含めて6桁で0埋め
    printf("フォーマット指定: %s\n", hexBuffer);

    return 0;
}

実行結果

10進数: 255 -> 16進数文字列: FF
フォーマット指定: 0x00ff

ソースコードの解説

  • char hexBuffer[20]:変換後の文字列を格納する場所です。サイズが小さすぎるとバッファオーバーフロー(メモリ破壊)を起こす危険があるため、余裕を持ったサイズにします。
  • %X:10進数の数値を、大文字の16進数文字列(0-9, A-F)に変換します。
  • %#06x# は「0x」を付けるフラグ、06 は「全体で6桁になるように0埋めする」指定です(0xの2文字分を含むので、数値部分は4桁になります)。

より安全な snprintf の使用を推奨

現在の開発標準では、バッファオーバーフローを防ぐために、書き込む最大文字数を指定できる snprintf の使用が強く推奨されます。

#include <stdio.h>

int main(void) {
    int num = 123456;
    char buf[10];

    // バッファサイズ(sizeof(buf))を指定して書き込む
    snprintf(buf, sizeof(buf), "%X", num);

    printf("変換結果: %s\n", buf);
    return 0;
}

ソースコードの解説

  • snprintf:第2引数にバッファのサイズを渡します。変換結果がこのサイズを超えそうな場合でも、はみ出さずに安全に途中で切り捨てられます。C言語での文字列操作における必須テクニックです。

変換せずに表示だけしたい場合(printf)

変数を文字列として保存する必要がなく、単にデバッグやログ表示のために画面に16進数で出したいだけであれば、printf 関数で直接指定子を使えば済みます。

%x と %X 指定子の活用

#include <stdio.h>

int main(void) {
    int num = 255;

    // そのまま表示
    printf("10進数: %d\n", num);
    
    // 16進数(小文字)で表示
    printf("16進数(小文字): %x\n", num);
    
    // 16進数(大文字)で表示
    printf("16進数(大文字): %X\n", num);
    
    // 0x を付けて表示
    printf("0x付き: %#x\n", num);

    return 0;
}

実行結果

10進数: 255
16進数(小文字): ff
16進数(大文字): FF
0x付き: 0xff

ソースコードの解説

  • printf の中で %x を使うだけで、内部的に保持されている数値データが16進数形式でコンソールに出力されます。変数の値自体が書き換わるわけではありません。

C言語のスキルを活かして年収を上げる方法

以上、C言語で16進数と10進数を相互に変換する方法について解説してきました。

なお、C言語のスキルがある場合には、「転職して年収をアップさせる」「副業で稼ぐ」といった方法を検討するのがおすすめです。

C言語を扱えるエンジニアは比較的希少価値が高く、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。

なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。

今すぐ転職する気がなくとも、とりあえず転職エージェントに無料登録しておくだけで、スカウトが届いたり、思わぬ好待遇の求人情報が送られてきたりするというメリットがあります。

併せて、副業案件を獲得できるエージェントにも登録しておくと、空いている時間を活かして稼げるようなC言語の案件を探しやすくなります。

転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。