C#の16進数変換・表記を完全解説|文字列・数値の変換方法とよくあるエラー対策
はじめに
C#で16進数を扱う場面は、思った以上に多くあります。たとえば、カラーコード、文字コード、バイト配列、ファイルのバイナリデータ、通信データ、ハッシュ値、デバッグログなどでは、数値やバイナリを16進数で表すと読みやすくなります。
C#では、16進数の数値リテラルを書く方法、数値を16進数文字列へ変換する方法、16進数文字列を数値へ戻す方法、byte配列と16進数文字列を相互変換する方法が用意されています。ただし、「0x付きの文字列がParseできない」「負の数を16進数にすると想定外の表示になる」「奇数桁の16進数文字列で例外が出る」といったつまずきもよくあります。
この記事では、C#の16進数変換・表記について、基本から実務で使いやすい実装例までまとめて解説します。
1. C#の16進数とは?基本の考え方と使いどころ
1-1. 16進数の基礎:0〜9とA〜Fで数値を表す仕組み
16進数は、0から15までの値を1桁で表す数値表現です。10進数では0〜9の10種類の数字を使いますが、16進数では0〜9に加えてA〜Fを使います。
| 10進数 | 16進数 |
|---|---|
| 0 | 0 |
| 1 | 1 |
| 9 | 9 |
| 10 | A |
| 11 | B |
| 12 | C |
| 13 | D |
| 14 | E |
| 15 | F |
| 16 | 10 |
たとえば、10進数の255は16進数ではFFです。これは、15×16 + 15 = 255 になるためです。
C#int value = 255;
Console.WriteLine(value.ToString("X")); // FF
C#で「c# 16進数」と調べると、多くの場合はこのような数値と文字列の変換方法を知りたいケースが多いです。
1-2. C#で16進数が使われる主な場面
C#で16進数が使われる代表的な場面は次のとおりです。
| 用途 | 例 |
|---|---|
| カラーコード | #FF0000、0xFF0000 |
| バイト配列 | byte[]を0A1B2Cのように表示 |
| 文字コード | UnicodeのU+3042など |
| ファイル解析 | バイナリデータの16進数ダンプ |
| 通信データ | パケットやプロトコルの確認 |
| ハッシュ値 | SHA256などの結果表示 |
| デバッグ | フラグ値やメモリ値の確認 |
16進数は、2進数より短く、10進数よりビット単位の意味を把握しやすいという特徴があります。
1-3. 10進数・2進数・16進数の違い
同じ値でも、表記方法によって見え方が変わります。
| 10進数 | 2進数 | 16進数 |
|---|---|---|
| 10 | 1010 | A |
| 15 | 1111 | F |
| 16 | 10000 | 10 |
| 255 | 11111111 | FF |
16進数の1桁は、2進数の4桁に対応します。
F = 1111
FF = 1111 1111
そのため、バイト単位のデータを表すときは16進数がよく使われます。1バイトは8ビットなので、16進数では2桁で表せます。
byte 255 = 0xFF
byte 0 = 0x00
1-4. 大文字・小文字のA〜Fに違いはあるか
16進数では、A〜Fを大文字で書いても小文字で書いても意味は同じです。
FF = ff
A0 = a0
C#で数値を16進数文字列に変換するときは、書式指定子によって大文字・小文字を切り替えられます。
C#int value = 255;
Console.WriteLine(value.ToString("X")); // FF
Console.WriteLine(value.ToString("x")); // ff
一般的には、ログやバイナリ表示では大文字のXがよく使われますが、小文字で統一しても問題ありません。大切なのは、プロジェクト内で表記を統一することです。
1-5. 16進数に関するC#の代表的な処理一覧
C#で16進数を扱う主な処理は次のとおりです。
| やりたいこと | 主な方法 |
|---|---|
| 16進数リテラルを書く | 0xFF |
| 数値を16進数文字列にする | value.ToString("X") |
| 桁数を揃える | value.ToString("X2")、value.ToString("X8") |
| 16進数文字列をintにする | Convert.ToInt32(hex, 16) |
| 安全に変換する | int.TryParse(hex, NumberStyles.HexNumber, ...) |
| byte[]を16進数文字列にする | Convert.ToHexString(bytes) |
| 16進数文字列をbyte[]に戻す | Convert.FromHexString(hex) |
| 古い環境でbyte[]を変換する | BitConverter.ToString(bytes) |
2. C#で16進数を表記する方法
2-1. 16進数リテラルは「0x」を付けて書く
C#のコード内で16進数の数値リテラルを書く場合は、先頭に0xまたは0Xを付けます。
C#int value1 = 0xFF;
int value2 = 0XFF;
Console.WriteLine(value1); // 255
Console.WriteLine(value2); // 255
0xFFは見た目は16進数ですが、変数に入った後は通常の数値です。つまり、int value = 0xFF;と書いても、内部的には10進数の255と同じ値を持ちます。
C#int a = 255;
int b = 0xFF;
Console.WriteLine(a == b); // True
2-2. int・long・byteなど型ごとの16進数表記例
C#では、さまざまな整数型で16進数リテラルを使えます。
C#byte b = 0xFF;
short s = 0x7FFF;
int i = 0x7FFFFFFF;
long l = 0x7FFFFFFFFFFFFFFF;
uint ui = 0xFFFFFFFF;
ulong ul = 0xFFFFFFFFFFFFFFFF;
ただし、型の範囲を超える値は代入できません。
C#byte b1 = 0xFF; // OK: 255
// byte b2 = 0x100; // エラー: byteの範囲を超える
byteは0〜255までの値しか扱えないため、0x100、つまり10進数の256は代入できません。
2-3. 2進数リテラル「0b」との違い
C#では、16進数リテラルのほかに2進数リテラルも使えます。2進数の場合は先頭に0bまたは0Bを付けます。
C#int hex = 0xFF; // 16進数
int bin = 0b11111111; // 2進数
Console.WriteLine(hex); // 255
Console.WriteLine(bin); // 255
2進数はビット単位の意味を細かく見たいときに便利です。一方、16進数は短く書けるため、バイト列やカラーコードなどでよく使われます。
C#int flags = 0b0001_0010;
int color = 0xFF_00_00;
2-4. 桁区切り「_」を使った読みやすい書き方
C#では、数値リテラルの中に_を入れて桁を区切れます。これは数値の意味には影響せず、読みやすくするための記法です。
C#int value = 0xFF_EC_DE_5E;
Console.WriteLine(value);
バイト単位で区切ると、16進数の値を読みやすくできます。
C#uint color = 0xFF_33_66_CC;
この例では、ARGBのように1バイトごとのまとまりが見やすくなります。
2-5. 文字コードやUnicodeエスケープで使う16進数表記
C#では、文字コードを表す場面でも16進数が使われます。
C#char c = '\u3042';
Console.WriteLine(c); // あ
\u3042は、UnicodeのコードポイントU+3042を表します。これはひらがなの「あ」です。
サロゲートペアを含む文字など、より大きなコードポイントを扱う場合は\Uを使います。
C#string emoji = "\U0001F600";
Console.WriteLine(emoji); // 😀
また、文字列中で\xを使うこともできますが、読み取り桁数が文脈によって変わることがあるため、Unicode文字を明確に書きたい場合は\uや\Uを使うほうが安全です。
3. 数値を16進数文字列に変換する方法
3-1. ToString("X")で数値を16進数に変換する
C#で数値を16進数文字列に変換する基本は、ToString("X")です。
C#int value = 255;
string hex = value.ToString("X");
Console.WriteLine(hex); // FF
"X"は16進数形式で文字列化するための標準数値書式指定子です。整数型に対してよく使われます。
C#int value = 48879;
Console.WriteLine(value.ToString("X")); // BEEF
3-2. ToString("x")とToString("X")の違い
"X"を使うとA〜Fが大文字になり、"x"を使うと小文字になります。
C#int value = 255;
Console.WriteLine(value.ToString("X")); // FF
Console.WriteLine(value.ToString("x")); // ff
どちらを使っても値としての意味は同じです。ログや仕様書に合わせて使い分けましょう。
3-3. 桁数を指定してゼロ埋めする方法
16進数文字列の桁数を揃えたい場合は、"X2"や"X8"のように桁数を指定します。
C#int value = 15;
Console.WriteLine(value.ToString("X")); // F
Console.WriteLine(value.ToString("X2")); // 0F
Console.WriteLine(value.ToString("X4")); // 000F
byteを16進数で表す場合は、2桁に揃えるのが一般的です。
C#byte b = 10;
Console.WriteLine(b.ToString("X2")); // 0A
intを8桁の16進数で表示したい場合は、"X8"を使います。
C#int value = 255;
Console.WriteLine(value.ToString("X8")); // 000000FF
3-4. Convert.ToString(value, 16)を使う方法
Convert.ToString(value, 16)でも、数値を16進数文字列に変換できます。
C#int value = 255;
string hex = Convert.ToString(value, 16);
Console.WriteLine(hex); // ff
Convert.ToString(value, 16)は小文字で出力されます。大文字にしたい場合はToUpperInvariant()を使います。
C#int value = 255;
string hex = Convert.ToString(value, 16).ToUpperInvariant();
Console.WriteLine(hex); // FF
ただし、桁数指定やゼロ埋めを簡潔に書きたい場合は、ToString("X2")やToString("X8")のほうが使いやすいです。
3-5. string.Format・文字列補間で16進数を出力する方法
string.Formatや文字列補間でも、16進数形式を指定できます。
C#int value = 255;
string s1 = string.Format("{0:X}", value);
string s2 = $"{value:X}";
Console.WriteLine(s1); // FF
Console.WriteLine(s2); // FF
桁数を指定することもできます。
C#int value = 15;
Console.WriteLine($"{value:X2}"); // 0F
Console.WriteLine($"{value:X8}"); // 0000000F
ログ出力では、文字列補間を使うと読みやすくなります。
C#int address = 4096;
int data = 255;
Console.WriteLine($"Address=0x{address:X4}, Data=0x{data:X2}");
// Address=0x1000, Data=0xFF
3-6. byteを2桁の16進数文字列に変換する方法
byteは0〜255の値なので、16進数では必ず2桁以内に収まります。実務では、1桁の場合もゼロ埋めして2桁にすることが多いです。
C#byte b1 = 0;
byte b2 = 10;
byte b3 = 255;
Console.WriteLine(b1.ToString("X2")); // 00
Console.WriteLine(b2.ToString("X2")); // 0A
Console.WriteLine(b3.ToString("X2")); // FF
byte配列を1バイトずつ変換する場合も、"X2"が基本です。
C#byte[] bytes = { 0x00, 0x0A, 0xFF };
foreach (byte b in bytes)
{
Console.Write(b.ToString("X2"));
}
// 000AFF
4. 16進数文字列を数値に変換する方法
4-1. Convert.ToInt32(hex, 16)で変換する
16進数文字列をintに変換する基本的な方法は、Convert.ToInt32(hex, 16)です。
C#string hex = "FF";
int value = Convert.ToInt32(hex, 16);
Console.WriteLine(value); // 255
第2引数の16は、16進数として解釈するという意味です。
C#Console.WriteLine(Convert.ToInt32("10", 16)); // 16
Console.WriteLine(Convert.ToInt32("A", 16)); // 10
Console.WriteLine(Convert.ToInt32("FF", 16)); // 255
4-2. int.ParseとNumberStyles.HexNumberを使う方法
int.Parseを使う場合は、NumberStyles.HexNumberを指定します。
C#using System.Globalization;
string hex = "FF";
int value = int.Parse(hex, NumberStyles.HexNumber);
Console.WriteLine(value); // 255
NumberStyles.HexNumberを指定しないと、通常の10進数として解釈されるため、"FF"のような文字列は変換できません。
C#// int.Parse("FF"); // FormatException
4-3. int.TryParseで安全に変換する方法
ユーザー入力や外部データを変換する場合は、例外を避けるためにint.TryParseを使うのがおすすめです。
C#using System.Globalization;
string hex = "FF";
bool success = int.TryParse(
hex,
NumberStyles.HexNumber,
CultureInfo.InvariantCulture,
out int value);
if (success)
{
Console.WriteLine(value); // 255
}
else
{
Console.WriteLine("変換できませんでした");
}
TryParseは変換に失敗しても例外を投げず、falseを返します。入力値の妥当性が保証されない場合は、ParseよりもTryParseのほうが安全です。
4-4. 「0x」付き文字列を変換する際の注意点
C#の数値リテラルでは0xFFのように書けますが、int.ParseやConvert.ToInt32で文字列を変換する場合は注意が必要です。
C#string hex = "0xFF";
// int value = Convert.ToInt32(hex, 16); // FormatException
Convert.ToInt32(hex, 16)は、基本的に"FF"のような文字列を期待します。"0x"が付いている場合は、事前に取り除きます。
C#string hex = "0xFF";
if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
hex = hex[2..];
}
int value = Convert.ToInt32(hex, 16);
Console.WriteLine(value); // 255
#FF0000のようなカラーコードを扱う場合も、先頭の#を取り除いてから変換します。
4-5. byte・short・long・uintなど型別の変換方法
変換先の型に応じて、対応するメソッドを使います。
C#byte b = Convert.ToByte("FF", 16);
short s = Convert.ToInt16("7FFF", 16);
int i = Convert.ToInt32("7FFFFFFF", 16);
long l = Convert.ToInt64("7FFFFFFFFFFFFFFF", 16);
uint ui = Convert.ToUInt32("FFFFFFFF", 16);
ulong ul = Convert.ToUInt64("FFFFFFFFFFFFFFFF", 16);
Console.WriteLine(b); // 255
Console.WriteLine(ui); // 4294967295
Parseを使う場合も、型ごとのParseメソッドを使えます。
C#using System.Globalization;
byte b = byte.Parse("FF", NumberStyles.HexNumber);
uint ui = uint.Parse("FFFFFFFF", NumberStyles.HexNumber);
ただし、変換先の型の範囲を超える文字列を渡すとOverflowExceptionが発生します。
C#// byte b = Convert.ToByte("100", 16); // 256なのでOverflowException
4-6. 変換できない文字列を判定する方法
変換できるかどうかを判定するには、TryParseを使います。
C#using System.Globalization;
static bool IsHexInt(string text)
{
return int.TryParse(
text,
NumberStyles.HexNumber,
CultureInfo.InvariantCulture,
out _);
}
Console.WriteLine(IsHexInt("FF")); // True
Console.WriteLine(IsHexInt("GG")); // False
Console.WriteLine(IsHexInt("0xFF")); // False
0x付きも許可したい場合は、事前に正規化します。
C#using System.Globalization;
static bool IsHexIntAllowPrefix(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return false;
}
text = text.Trim();
if (text.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
text = text[2..];
}
return int.TryParse(
text,
NumberStyles.HexNumber,
CultureInfo.InvariantCulture,
out _);
}
5. バイト配列と16進数文字列を相互変換する方法
5-1. byte[]を16進数文字列に変換する基本パターン
byte[]を16進数文字列に変換する基本は、各byteを"X2"で変換して連結する方法です。
C#byte[] bytes = { 0x00, 0x0A, 0xFF };
var sb = new System.Text.StringBuilder();
foreach (byte b in bytes)
{
sb.Append(b.ToString("X2"));
}
string hex = sb.ToString();
Console.WriteLine(hex); // 000AFF
1バイトは16進数2桁で表せるため、"X2"でゼロ埋めするのがポイントです。
5-2. BitConverter.ToStringを使う方法
BitConverter.ToStringを使うと、byte配列を簡単に16進数文字列へ変換できます。
C#byte[] bytes = { 0x00, 0x0A, 0xFF };
string hex = BitConverter.ToString(bytes);
Console.WriteLine(hex); // 00-0A-FF
ただし、BitConverter.ToStringの結果にはハイフンが入ります。ログやデバッグでは見やすいですが、ハッシュ値やAPI送信用の文字列としてはハイフンなしにしたいこともあります。
5-3. ハイフンなしの連続した16進数文字列にする方法
BitConverter.ToStringの結果からハイフンを削除すれば、連続した16進数文字列にできます。
C#byte[] bytes = { 0x00, 0x0A, 0xFF };
string hex = BitConverter.ToString(bytes).Replace("-", "");
Console.WriteLine(hex); // 000AFF
ただし、頻繁に大量データを処理する場合は、Replaceによる追加処理が気になることもあります。その場合は、Convert.ToHexStringやStringBuilderを使う方法を検討しましょう。
5-4. Convert.ToHexStringを使う方法
.NET 5以降では、Convert.ToHexStringを使うとbyte配列を簡単にハイフンなしの16進数文字列へ変換できます。
C#byte[] bytes = { 0x00, 0x0A, 0xFF };
string hex = Convert.ToHexString(bytes);
Console.WriteLine(hex); // 000AFF
Convert.ToHexStringは、大文字の16進数文字列を返します。現在の.NET環境で使える場合は、byte配列から16進数文字列への変換として非常に便利です。
5-5. 16進数文字列をbyte[]に戻す方法
16進数文字列をbyte配列に戻すには、2文字ずつ取り出してConvert.ToByteで変換します。
C#string hex = "000AFF";
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
string part = hex.Substring(i * 2, 2);
bytes[i] = Convert.ToByte(part, 16);
}
Console.WriteLine(bytes[0]); // 0
Console.WriteLine(bytes[1]); // 10
Console.WriteLine(bytes[2]); // 255
16進数2桁が1バイトに対応するため、文字列の長さは偶数である必要があります。
5-6. Convert.FromHexStringを使う方法
.NET 5以降では、Convert.FromHexStringを使うと、16進数文字列を簡単にbyte配列へ変換できます。
C#string hex = "000AFF";
byte[] bytes = Convert.FromHexString(hex);
Console.WriteLine(bytes[0]); // 0
Console.WriteLine(bytes[1]); // 10
Console.WriteLine(bytes[2]); // 255
Convert.ToHexStringとConvert.FromHexStringを組み合わせると、byte配列と16進数文字列の相互変換を簡潔に書けます。
C#byte[] original = { 0xDE, 0xAD, 0xBE, 0xEF };
string hex = Convert.ToHexString(original);
byte[] restored = Convert.FromHexString(hex);
Console.WriteLine(hex); // DEADBEEF
Console.WriteLine(original.SequenceEqual(restored)); // True
5-7. 奇数桁や不正文字がある場合の対処法
16進数文字列をbyte配列に変換する場合、文字列の長さが奇数だと1バイトに分割できません。
C#string hex = "ABC"; // 3桁なので不正
このような場合は、事前にチェックします。
C#static bool IsValidHexByteString(string hex)
{
if (string.IsNullOrWhiteSpace(hex))
{
return false;
}
hex = hex.Trim();
if (hex.Length % 2 != 0)
{
return false;
}
foreach (char c in hex)
{
bool isHex =
('0' <= c && c <= '9') ||
('a' <= c && c <= 'f') ||
('A' <= c && c <= 'F');
if (!isHex)
{
return false;
}
}
return true;
}
Convert.FromHexStringを使う場合も、不正な文字列では例外が発生します。外部入力を扱う場合は、事前チェックまたは例外処理を入れると安全です。
6. C#の16進数変換でよくあるエラーと対策
6-1. FormatExceptionが発生する原因と解決方法
FormatExceptionは、文字列の形式が正しくないときに発生します。
C#// Convert.ToInt32("GG", 16); // FormatException
// Convert.ToInt32("0xFF", 16); // FormatException
原因として多いのは次のケースです。
| 原因 | 対策 |
|---|---|
| GやZなど16進数でない文字が含まれる | 入力値をチェックする |
0xが付いている | 事前に取り除く |
#が付いている | カラーコードなら先頭の#を取り除く |
| 空白や改行が混ざる | Trim()する |
| 空文字 | 事前に空チェックする |
安全に処理するなら、TryParseを使います。
C#using System.Globalization;
string input = "FF";
if (int.TryParse(input, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int value))
{
Console.WriteLine(value);
}
else
{
Console.WriteLine("16進数として変換できません");
}
6-2. OverflowExceptionが発生する原因と解決方法
OverflowExceptionは、変換先の型に収まらない値を変換しようとしたときに発生します。
C#// byte b = Convert.ToByte("100", 16); // 256なのでOverflowException
byteの最大値は255、つまり16進数ではFFです。100は16進数で256を意味するため、byteには入りません。
対策としては、より大きな型へ変換するか、事前に範囲チェックを行います。
C#int value = Convert.ToInt32("100", 16);
if (value <= byte.MaxValue)
{
byte b = (byte)value;
Console.WriteLine(b);
}
else
{
Console.WriteLine("byteの範囲を超えています");
}
6-3. 「0x」が付いているとParseできない場合の対処
0xFFという表記はC#のコード上では有効ですが、文字列としてParseする場合はそのままでは失敗することがあります。
C#using System.Globalization;
string input = "0xFF";
// int.Parse(input, NumberStyles.HexNumber); // FormatException
この場合は、0xを削除してから変換します。
C#using System.Globalization;
string input = "0xFF";
string hex = input.Trim();
if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
hex = hex[2..];
}
int value = int.Parse(hex, NumberStyles.HexNumber);
Console.WriteLine(value); // 255
0XFFのように大文字のXが使われることもあるため、StringComparison.OrdinalIgnoreCaseで判定すると便利です。
6-4. マイナス値を16進数に変換したときの注意点
負の数をToString("X")で16進数に変換すると、2の補数表現に基づいた表示になります。
C#int value = -1;
Console.WriteLine(value.ToString("X")); // FFFFFFFF
これは、int型の-1がビット表現としては全ビット1になるためです。
C#short s = -1;
int i = -1;
long l = -1;
Console.WriteLine(s.ToString("X")); // FFFF
Console.WriteLine(i.ToString("X")); // FFFFFFFF
Console.WriteLine(l.ToString("X")); // FFFFFFFFFFFFFFFF
「符号付きの値として-1のように表示したい」のか、「ビットパターンとしてFFFFFFFFを見たい」のかによって、扱い方を分ける必要があります。
6-5. 大文字・小文字・空白・改行が混ざる場合の処理
16進数文字列では、大文字と小文字はどちらでも変換できます。
C#Console.WriteLine(Convert.ToInt32("ff", 16)); // 255
Console.WriteLine(Convert.ToInt32("FF", 16)); // 255
ただし、前後に空白や改行がある場合は、Trim()しておくと安全です。
C#string input = " FF\r\n ";
int value = Convert.ToInt32(input.Trim(), 16);
Console.WriteLine(value); // 255
バイト列のように途中に空白が入っている場合は、必要に応じて削除します。
C#string input = "DE AD BE EF";
string hex = input.Replace(" ", "");
byte[] bytes = Convert.FromHexString(hex);
Console.WriteLine(Convert.ToHexString(bytes)); // DEADBEEF
6-6. nullや空文字を変換するときの安全な書き方
nullや空文字をそのまま変換しようとすると、例外や意図しない結果につながります。
C#string? input = null;
if (string.IsNullOrWhiteSpace(input))
{
Console.WriteLine("入力が空です");
}
else
{
int value = Convert.ToInt32(input, 16);
Console.WriteLine(value);
}
実務では、次のように正規化処理とTryParseを組み合わせると安全です。
C#using System.Globalization;
static bool TryParseHexInt(string? input, out int value)
{
value = 0;
if (string.IsNullOrWhiteSpace(input))
{
return false;
}
string hex = input.Trim();
if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
hex = hex[2..];
}
return int.TryParse(
hex,
NumberStyles.HexNumber,
CultureInfo.InvariantCulture,
out value);
}
7. 用途別に見るC#の16進数変換サンプル
7-1. カラーコードを数値やRGBに変換する
カラーコード#FF3366をRGBに分解する例です。
C#string colorCode = "#FF3366";
string hex = colorCode.TrimStart('#');
int r = Convert.ToInt32(hex.Substring(0, 2), 16);
int g = Convert.ToInt32(hex.Substring(2, 2), 16);
int b = Convert.ToInt32(hex.Substring(4, 2), 16);
Console.WriteLine($"R={r}, G={g}, B={b}");
// R=255, G=51, B=102
RGB値からカラーコードを作る場合は、"X2"で2桁に揃えます。
C#int r = 255;
int g = 51;
int b = 102;
string colorCode = $"#{r:X2}{g:X2}{b:X2}";
Console.WriteLine(colorCode); // #FF3366
7-2. 文字列の各文字を16進数コードで表示する
文字列の各文字をUnicodeコードで表示する例です。
C#string text = "ABCあ";
foreach (char c in text)
{
Console.WriteLine($"{c} = U+{(int)c:X4}");
}
出力例です。
A = U+0041
B = U+0042
C = U+0043
あ = U+3042
サロゲートペアを含む文字を正しくコードポイントとして扱いたい場合は、Runeを使う方法もあります。
C#using System.Text;
string text = "😀";
foreach (var rune in text.EnumerateRunes())
{
Console.WriteLine($"U+{rune.Value:X}");
}
7-3. ファイルや通信データを16進数ダンプする
ファイルや通信データを確認するときは、byte配列を16進数で出力すると便利です。
C#byte[] data = { 0x48, 0x65, 0x6C, 0x6C, 0x6F };
for (int i = 0; i < data.Length; i++)
{
Console.Write($"{data[i]:X2} ");
}
// 48 65 6C 6C 6F
アドレス風に表示する簡単な16進数ダンプ例です。
C#byte[] data = Enumerable.Range(0, 64).Select(i => (byte)i).ToArray();
for (int i = 0; i < data.Length; i += 16)
{
Console.Write($"{i:X4}: ");
for (int j = 0; j < 16 && i + j < data.Length; j++)
{
Console.Write($"{data[i + j]:X2} ");
}
Console.WriteLine();
}
7-4. ハッシュ値やバイナリデータを16進数で表示する
ハッシュ値はbyte配列で得られることが多いため、16進数文字列に変換して表示します。
C#using System.Security.Cryptography;
using System.Text;
string text = "hello";
byte[] bytes = Encoding.UTF8.GetBytes(text);
byte[] hash = SHA256.HashData(bytes);
string hex = Convert.ToHexString(hash);
Console.WriteLine(hex);
小文字で表示したい場合は、ToLowerInvariant()を使います。
C#string hexLower = Convert.ToHexString(hash).ToLowerInvariant();
Console.WriteLine(hexLower);
7-5. Unicodeコードポイントを16進数で扱う
Unicodeコードポイントは、U+3042のように16進数で表されます。
C#int codePoint = 0x3042;
string text = char.ConvertFromUtf32(codePoint);
Console.WriteLine(text); // あ
逆に、文字からコードポイントを取得する場合は次のように書けます。
C#string text = "あ";
int codePoint = char.ConvertToUtf32(text, 0);
Console.WriteLine($"U+{codePoint:X4}"); // U+3042
絵文字のように1つの文字が複数のcharで構成される場合があるため、Unicodeを本格的に扱う場合はchar単位ではなくコードポイント単位で考えることが重要です。
7-6. デバッグログに16進数を出力する
デバッグログでは、10進数と16進数を併記すると原因調査がしやすくなります。
C#int status = 255;
Console.WriteLine($"Status={status} (0x{status:X2})");
// Status=255 (0xFF)
フラグやビットマスクを扱う場合は、16進数で表示するとビットパターンを把握しやすくなります。
C#int flags = 0b1010_0101;
Console.WriteLine($"Flags=0x{flags:X2}");
// Flags=0xA5
8. C#の16進数変換で使うメソッド比較
8-1. ToString("X")とConvert.ToStringの違い
数値を16進数文字列にする方法として、ToString("X")とConvert.ToString(value, 16)があります。
| 方法 | 出力例 | 特徴 |
|---|---|---|
value.ToString("X") | FF | 大文字、桁数指定が簡単 |
value.ToString("x") | ff | 小文字、桁数指定が簡単 |
Convert.ToString(value, 16) | ff | 基数を指定できる |
実務では、桁数を揃えたいことが多いため、ToString("X2")やToString("X8")がよく使われます。
C#int value = 15;
Console.WriteLine(value.ToString("X2")); // 0F
Console.WriteLine(Convert.ToString(value, 16)); // f
8-2. ParseとTryParseの使い分け
Parseは変換できないと例外を投げます。入力が必ず正しいと分かっている場合に向いています。
C#using System.Globalization;
int value = int.Parse("FF", NumberStyles.HexNumber);
TryParseは変換に失敗しても例外を投げません。ユーザー入力、外部ファイル、APIレスポンスなどを扱う場合に向いています。
C#using System.Globalization;
if (int.TryParse("FF", NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int value))
{
Console.WriteLine(value);
}
基本的には、外部入力にはTryParse、固定値やテストコードにはParseという使い分けがおすすめです。
8-3. BitConverterとConvert.ToHexStringの違い
byte配列を16進数文字列にする方法として、BitConverter.ToStringとConvert.ToHexStringがあります。
| 方法 | 出力例 | 特徴 |
|---|---|---|
BitConverter.ToString(bytes) | DE-AD-BE-EF | ハイフン付き |
Convert.ToHexString(bytes) | DEADBEEF | ハイフンなし |
| 自作ループ | DEADBEEF | 古い環境でも使える |
Convert.ToHexStringが使える環境では、ハイフンなしの16進数文字列を簡単に作れるため便利です。
C#byte[] bytes = { 0xDE, 0xAD, 0xBE, 0xEF };
Console.WriteLine(BitConverter.ToString(bytes)); // DE-AD-BE-EF
Console.WriteLine(Convert.ToHexString(bytes)); // DEADBEEF
8-4. Convert.FromHexStringと自作変換処理の違い
16進数文字列をbyte配列に戻す場合、.NET 5以降ならConvert.FromHexStringが簡潔です。
C#byte[] bytes = Convert.FromHexString("DEADBEEF");
古い環境や、スペース・ハイフン・0xなどを許容したい場合は、自作で正規化してから変換します。
C#string input = "DE-AD-BE-EF";
string hex = input.Replace("-", "");
byte[] bytes = Convert.FromHexString(hex);
自作処理では柔軟な入力に対応できますが、バグを生みやすい点に注意が必要です。使える環境であれば、標準メソッドを優先するのがおすすめです。
8-5. 処理速度・可読性・対応バージョンで選ぶ方法
16進数変換の方法は、可読性、処理速度、対応バージョンで選ぶとよいです。
| 目的 | おすすめ |
|---|---|
| 数値を16進数文字列にする | ToString("X") |
| 桁数を揃える | ToString("X2")、ToString("X8") |
| 16進数文字列を数値にする | TryParseまたはConvert.ToInt32 |
| byte[]を16進数文字列にする | Convert.ToHexString |
| 16進数文字列をbyte[]にする | Convert.FromHexString |
| 古い.NETでbyte[]を変換する | BitConverter.ToStringまたは自作 |
| 外部入力を安全に扱う | 正規化 + TryParse |
最新の.NETを使えるなら、byte配列の変換にはConvert.ToHexStringとConvert.FromHexStringを使うと、コードが短く読みやすくなります。
9. 実務で使いやすい16進数変換の実装例
9-1. 数値を固定桁の16進数に変換する関数
数値を固定桁の16進数文字列にする関数です。
C#static string ToHex(int value, int digits)
{
return value.ToString($"X{digits}");
}
Console.WriteLine(ToHex(15, 2)); // 0F
Console.WriteLine(ToHex(255, 4)); // 00FF
Console.WriteLine(ToHex(4096, 8)); // 00001000
0x付きで出力したい場合は、次のようにします。
C#static string ToHexWithPrefix(int value, int digits)
{
return $"0x{value.ToString($"X{digits}")}";
}
Console.WriteLine(ToHexWithPrefix(255, 2)); // 0xFF
9-2. 16進数文字列を安全にintへ変換する関数
0x付き、前後空白ありの入力にも対応した安全な変換関数です。
C#using System.Globalization;
static bool TryHexToInt(string? input, out int value)
{
value = 0;
if (string.IsNullOrWhiteSpace(input))
{
return false;
}
string hex = input.Trim();
if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
hex = hex[2..];
}
return int.TryParse(
hex,
NumberStyles.HexNumber,
CultureInfo.InvariantCulture,
out value);
}
if (TryHexToInt("0xFF", out int result))
{
Console.WriteLine(result); // 255
}
ユーザー入力や設定ファイルの値を扱う場合は、このように例外を出さない実装にしておくと安全です。
9-3. byte[]をハイフンなし16進数文字列に変換する関数
.NET 5以降なら、次の関数で十分です。
C#static string BytesToHex(byte[] bytes)
{
return Convert.ToHexString(bytes);
}
byte[] bytes = { 0xDE, 0xAD, 0xBE, 0xEF };
Console.WriteLine(BytesToHex(bytes)); // DEADBEEF
小文字にしたい場合は、ToLowerInvariant()を使います。
C#static string BytesToHexLower(byte[] bytes)
{
return Convert.ToHexString(bytes).ToLowerInvariant();
}
Console.WriteLine(BytesToHexLower(bytes)); // deadbeef
古い.NET環境では、StringBuilderで実装できます。
C#static string BytesToHexLegacy(byte[] bytes)
{
var sb = new System.Text.StringBuilder(bytes.Length * 2);
foreach (byte b in bytes)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
9-4. 16進数文字列をbyte[]へ変換する関数
.NET 5以降なら、Convert.FromHexStringを使うのが簡単です。
C#static byte[] HexToBytes(string hex)
{
return Convert.FromHexString(hex);
}
byte[] bytes = HexToBytes("DEADBEEF");
Console.WriteLine(bytes.Length); // 4
入力に空白やハイフンが混ざる可能性がある場合は、事前に取り除きます。
C#static byte[] HexToBytesFlexible(string input)
{
if (input is null)
{
throw new ArgumentNullException(nameof(input));
}
string hex = input
.Trim()
.Replace(" ", "")
.Replace("-", "");
if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
hex = hex[2..];
}
return Convert.FromHexString(hex);
}
byte[] bytes = HexToBytesFlexible("DE-AD-BE-EF");
Console.WriteLine(Convert.ToHexString(bytes)); // DEADBEEF
9-5. 不正な入力を考慮した汎用的な変換処理
例外を投げずに、16進数文字列をbyte配列へ変換できるか判定する関数です。
C#static bool TryHexToBytes(string? input, out byte[] bytes)
{
bytes = Array.Empty<byte>();
if (string.IsNullOrWhiteSpace(input))
{
return false;
}
string hex = input
.Trim()
.Replace(" ", "")
.Replace("-", "");
if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
hex = hex[2..];
}
if (hex.Length == 0 || hex.Length % 2 != 0)
{
return false;
}
foreach (char c in hex)
{
bool isHex =
('0' <= c && c <= '9') ||
('a' <= c && c <= 'f') ||
('A' <= c && c <= 'F');
if (!isHex)
{
return false;
}
}
try
{
bytes = Convert.FromHexString(hex);
return true;
}
catch
{
bytes = Array.Empty<byte>();
return false;
}
}
使用例です。
C#if (TryHexToBytes("DE AD BE EF", out byte[] bytes))
{
Console.WriteLine(Convert.ToHexString(bytes)); // DEADBEEF
}
else
{
Console.WriteLine("不正な16進数文字列です");
}
外部入力では、空文字、奇数桁、不正文字、0x、空白、ハイフンなどを考慮しておくと、実務でトラブルを減らせます。
10. C#の16進数に関するよくある質問
10-1. C#で16進数の先頭に0xは必要?
C#のコード内で16進数リテラルを書く場合は、先頭に0xが必要です。
C#int value = 0xFF;
一方、文字列として16進数を扱う場合は、必ずしも0xは必要ありません。
C#string hex = "FF";
int value = Convert.ToInt32(hex, 16);
むしろ、Convert.ToInt32(hex, 16)やint.Parseでは、0xが付いていると変換できないことがあるため注意が必要です。
10-2. 16進数文字列に0xが付いているときはどう変換する?
0xを取り除いてから変換します。
C#string input = "0xFF";
string hex = input.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
? input[2..]
: input;
int value = Convert.ToInt32(hex, 16);
Console.WriteLine(value); // 255
前後に空白がある可能性がある場合は、先にTrim()します。
C#string input = " 0xFF ";
string hex = input.Trim();
if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
hex = hex[2..];
}
int value = Convert.ToInt32(hex, 16);
10-3. 16進数を10進数に変換するには?
Convert.ToInt32(hex, 16)を使います。
C#string hex = "FF";
int value = Convert.ToInt32(hex, 16);
Console.WriteLine(value); // 255
安全に変換したい場合は、int.TryParseを使います。
C#using System.Globalization;
string hex = "FF";
if (int.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int value))
{
Console.WriteLine(value); // 255
}
10-4. 10進数を16進数に変換するには?
数値に対してToString("X")を使います。
C#int value = 255;
string hex = value.ToString("X");
Console.WriteLine(hex); // FF
小文字にしたい場合は"x"を使います。
C#Console.WriteLine(value.ToString("x")); // ff
10-5. byte配列を16進数文字列にする最短の方法は?
.NET 5以降なら、Convert.ToHexStringが最短で読みやすい方法です。
C#byte[] bytes = { 0xDE, 0xAD, 0xBE, 0xEF };
string hex = Convert.ToHexString(bytes);
Console.WriteLine(hex); // DEADBEEF
古い環境では、BitConverter.ToStringを使う方法があります。
C#string hex = BitConverter.ToString(bytes).Replace("-", "");
Console.WriteLine(hex); // DEADBEEF
10-6. C#で16進数の桁数を揃えるには?
ToString("X2")やToString("X8")のように、Xの後ろに桁数を指定します。
C#int value = 15;
Console.WriteLine(value.ToString("X2")); // 0F
Console.WriteLine(value.ToString("X4")); // 000F
Console.WriteLine(value.ToString("X8")); // 0000000F
byteは2桁、shortは4桁、intは8桁、longは16桁で表示すると、ビット幅に合わせやすくなります。
C#byte b = 255;
short s = 255;
int i = 255;
long l = 255;
Console.WriteLine(b.ToString("X2")); // FF
Console.WriteLine(s.ToString("X4")); // 00FF
Console.WriteLine(i.ToString("X8")); // 000000FF
Console.WriteLine(l.ToString("X16")); // 00000000000000FF
10-7. 負の数を16進数にするとどう表示される?
負の数をToString("X")で16進数にすると、型のビット幅に応じた2の補数表現で表示されます。
C#int value = -1;
Console.WriteLine(value.ToString("X")); // FFFFFFFF
short、int、longでは表示される桁数が異なります。
C#short s = -1;
int i = -1;
long l = -1;
Console.WriteLine(s.ToString("X")); // FFFF
Console.WriteLine(i.ToString("X")); // FFFFFFFF
Console.WriteLine(l.ToString("X")); // FFFFFFFFFFFFFFFF
負の数を扱う場合は、符号付きの値として見たいのか、ビットパターンとして見たいのかを明確にしておくことが重要です。
まとめ
C#で16進数を扱う基本は、数値リテラルでは0x、数値から16進数文字列への変換ではToString("X")、16進数文字列から数値への変換ではConvert.ToInt32(hex, 16)やint.TryParseを使うことです。
byte配列を16進数文字列に変換する場合は、.NET 5以降ならConvert.ToHexStringが便利です。逆に、16進数文字列をbyte配列へ戻す場合はConvert.FromHexStringを使うと簡潔に書けます。
一方で、実務では0x付き文字列、空白や改行、不正文字、奇数桁、型の範囲超過、負の数の表示などに注意が必要です。外部入力を扱う場合は、Trim()やプレフィックス除去で入力を正規化し、TryParseや事前チェックを使って安全に変換しましょう。
C#の16進数変換は、カラーコード、文字コード、バイナリデータ、ハッシュ値、通信ログ、デバッグ出力など幅広い場面で役立ちます。基本的な変換方法とエラー対策を押さえておけば、数値やバイト列を扱うコードをより読みやすく、安定して実装できます。

