【C言語】printfで文字の色や背景色を変更する

printfで文字色や背景色を変更する方法の解説ページアイキャッチ

このページにはプロモーションが含まれています

このページでは、printf で「文字の色や背景色を変更する」方法について解説します。

これにより、下の図のように printf で出力した文字の色や背景色を変化させ、例えばエラーであることや警告であることを分かりやすくしたり、色を利用することで作成できるプログラムの幅を広げることもできます。

printfでの出力文字の色を変更する様子

といっても、この文字の色や背景色の変更は、C言語の printf そのものの機能ではなく、printf の出力先、例えばターミナルやコマンドプロント等における機能になります(このページでは、printf の出力先がターミナルであることを前提に解説していきます)。

具体的には、文字の色や背景色を変更するためにC言語のソースコードで行うことは、printf でのエスケープシーケンス(命令みたいなもの)の出力になります。これにより、以降の printf での文字列の出力時に、ターミナルが事前に出力されたエスケープシーケンスに応じて文字の色や背景色を変更してくれます。

ターミナルが出力されたエスケープシーケンスに従って色を変更する様子

色を変更してくれるのはターミナルですので、printf の出力先となるターミナルが色の変更に対応していなかったり、指定するエスケープシーケンスに対応していない場合などは、色の変更ができないので注意してください。

ちなみに、改行を行う際に利用する \n もエスケープシーケンスの1つになります。エスケープシーケンス自体については下記ページで解説していますので、エスケープシーケンスについて知りたい方はこちらを参考にしていただければと思います。

エスケープシーケンスの解説ページアイキャッチ 【C言語】エスケープシーケンスで特殊文字を扱う

また、私は Mac を使用しており、Mac のターミナルを利用して動作確認を行なっています。おそらく Linux のターミナルでも同様の方法で色の変更を行うことができると思いますが、Windows のコマンドプロンプト等は対応していない可能性もあるので注意してください(対応しているかどうかは、実際に以降で紹介するソースコードのプログラムを実行してみれば確認できます)。

printf で文字の色や背景色を変更する方法

前述の通り、printf で文字の色や背景色を変更する際にはエスケープシーケンスを利用します。

具体的にどのようなエスケープシーケンスを利用するのか確認していきましょう!

文字の色や背景色を変更するエスケープシーケンス

文字の色や背景色を変更する際には、printf で下の図のようなエスケープシーケンスを出力します。

文字色や背景色等を変更するエスケープシーケンス

<code> の部分で、どのように色を変更するかを指定します。printf で上記エスケープシーケンスを出力すると、それ以降ターミナルに表示される文字の色や背景色が、出力されたエスケープシーケンスに応じて変化することになります。

また、\x1b の部分は \033\e に置き換えても良いようです。このページでは \x1b で統一して解説していきたいと思います。

例えば、<code>31 を指定して上記エスケープシーケンスを出力し、その後てきとうな文字列を出力してみましょう!<code>31 を指定することで、文字の色を赤に変更することができるはずです。

これは、例えば下記のようにソースコードを記述することで実現することができます。

文字の色の変更
#include <stdio.h>

int main(void) {
    printf("Hello World!");
    printf("\x1b[31m");
    printf("Hello!\n");
    printf("Good Bye\n");
    printf("Good Morning\n");
}

上記のソースコードをコンパイルして実行してみてください。文字の色が変化しているでしょうか?

私の場合は下の図のように文字列が出力されました。文字の色が途中から赤に変化していることが確認できると思います。

文字の色が赤色に変化する様子

スポンサーリンク

色の変更のリセット

上の図の結果を見ても分かるとおり、色が変化するのは \x1b[<code>m の出力以降になります。逆に、\x1b[<code>m の出力以降はずっと色が変化していることになります(おそらくプログラム終了まで)。

ただ、\x1b[<code>m 以降ずっと同じ色になってしまうのも不便ですよね…。

これを解決するために、下記のようなリセットを行うためのエスケープシーケンスも用意されています。

  • \x1b[0m:全ての変更を元に戻す
  • \x1b[39m:文字の色を元に戻す
  • \x1b[49m:背景色を元に戻す
  • \x1b[m:全ての変更を元に戻す(?)

\x1b[<code>m を出力して色を変更した後でも、\x1b[0m 等でリセットを行うことで色の変更を取り消すことができます。

文字が赤色になる期間を示した図

したがって、下記のようにソースコードを記述すれば、Hello! のみ文字の色が赤に変化し、それ以外は文字の色が元のままの状態で出力されることになります。

リセット
#include <stdio.h>

int main(void) {
    printf("Hello World!");
    printf("\x1b[31m");
    printf("Hello!\n");
    printf("\x1b[0m");
    printf("Good Bye\n");
    printf("Good Morning\n");
}

実際に私が試した結果は下の図になります。

文字の色が途中で元に戻る様子

色を変更する際には、色を変更するエスケープシーケンス \x1b[<code>m の出力だけでなく、リセットを行う出力も重要になりますので、その点はご注意ください。特に \x1b[0m は覚えておくと良いと思います。

また、前述の通り、色が変化するのは \x1b[<code>m の出力以降です。ですので、わざわざ上記のソースコードのように \x1b[31m 等のエスケープシーケンスと通常の文字列の出力を別の printf で行う必要もなく、1つの printf の中でエスケープシーケンスによる色の変更と文字列出力を行うこともできます。

エスケープシーケンスと文字出力の同時実行
#include <stdio.h>

int main(void) {
    printf("Hello World!");
    printf("\x1b[31mHello!\n\x1b[0m");
    printf("Good Bye\n");
    printf("Good Morning\n");
}

"\x1b[31mHello!\n\x1b[0m" がちょっとややこしいですが、下の図のように分けて考えると、各部がどのような役割を果たしているかが分かりやすくなるかと思います。

printfで出力するデータの各部の役割

<code> を複数同時に指定する方法

ここまでの例では <code> を1つのみ指定してきましたが、同時に複数指定することも可能です。これにより、例えば文字の色と背景色を同時に変更するようなことができます。

<code> を複数指定する場合、<code>; 区切りで指定します。例えば下記は、<code> を3つ同時に指定する例になります。

codeの複数指定
\x1b[<code>;<code>;<code>m

例えば、<code> として 3142 を同時に指定する場合は下記のように記述をして printf で出力を行います。31 は文字の色を赤に変更する数値であり、42 は背景色を緑に変更する数値になります。

codeの複数指定例
printf("Hello!\x1b[31;42mHello!\x1b[0mHello!\n");

私の場合、実行結果は下の図のようになりました。文字の色と背景色を同時に変更することができていることが確認できると思います。

文字の色と背景の色を同時に変更する様子

<code> に指定可能な数値の調べ方

ここまで <code> には 3142 などを指定してきましたが、他にも指定可能な数値はたくさん存在します。

<code> に指定可能な代表的な数値を下記で示しておきます。

  • 31:文字の色を赤に変更
  • 32:文字の色を緑に変更
  • 33:文字の色を黄に変更
  • 34:文字の色を青に変更
  • 35:文字の色をマゼンタに変更
  • 36:文字の色をシアンに変更
  • 37:文字の色をグレーに変更
  • 41:背景の色を赤に変更
  • 42:背景の色を緑に変更
  • 43:背景の色を黄に変更
  • 44:背景の色を青に変更
  • 45:背景の色をマゼンタに変更
  • 46:背景の色をシアンに変更
  • 47:背景の色をグレーに変更

ただ、使用しているターミナルによって対応する <code> や、その <code> を指定した時の出力結果(色味など)が異なります。なので、<code> に何を指定すれば出力がどのように変化するかを明確に伝えるのが難しいです。

そのため、<code> に指定可能な値や <code> に指定した値によってどのように出力が変化するかについては、あなた自身で確認してみていただくのが一番良いと思います。

その方法は簡単で、<code> に指定可能な値の全パターンを実際に試し、その出力結果を確認してみれば良いだけです。

そしてこれは、下記のソースコードを実行することで実現することができます。

全パターンの確認
#include <stdio.h>

int main(void) {
    
    for (int i = 0; i < 12; i++) {
        for (int j = 0; j < 10; j++) {
           printf("\x1b[%dm %03d \x1b[0m", i * 10 + j, i * 10 + j);
        }
        printf("\n");
    }
}

上記では、\x1b[<code>m<code> 部分に 0119 までの値を当てはめながら色等の変更を行なっています。そして、変更後に <code> に指定した値を3桁で表示しています(おそらく 0119 のみで足りるはず)。

わざわざ2重ループにしているのは、出力結果を綺麗に並べるためです(内側のループが終了するたびに改行するようにしている)。

上記ソースコードをコンパイルして実行すれば、下の図のように <code> に全パターンを指定した結果が並べて表示されます。

<code>による出力結果を羅列した様子

出力されている数値が、その数値を出力するときに指定した <code> になります。ですので、例えば下の図の箇所を確認すれば、文字の色を緑に変更するためには <code>32 を指定すれば良いことが確認できます(先頭の 0 の指定は不要です)。

文字の色を変更するための<code>を調べる様子

したがって、文字の色を緑に変更したいのであれば、文字列を出力する前に \x1b[32m を出力してやれば良いことになります。

文字の色を緑に変更する
printf("\x1b[32mHello!\n");

また、実際に全パターンの表示を行うと確認できると思いますが、実はエスケープシーケンスでは文字の色や背景色だけでなく、斜体設定や下線設定なども行うことができます(なぜか 001 が表示されていないが、1 は太字設定のはず)。

変更が可能なのが色だけではないことを示す図

例えば下記のように printf を実行すれば、Hello! がマゼンタ色かつ、太字&下線付きで出力されることになります。

マゼンタ・太字・下線付き
printf("\x1b[35;1;4mHello!\n");

こんな感じで、<code> の全パターンを実際に試してやれば、自身が望む文字の出力形式にするために <code> に何を指定すれば良いかを簡単に確認することができます。

ただし、前述の通り出力先によって見え方が異なる場合があるので注意してください。例えば、私は Mac 標準のターミナルアプリと VSCode 付属のターミナルの両方で出力結果を試してみましたが、この2つでも色味などが結構異なりました。

実際の両者の出力結果は下記のようになります。小さくて分かりくいかもしれませんが、044 のあたりは両者の違いが分かりやすいのではないかと思います。

ターミナルアプリとVSCodeのターミナルとの出力結果の違い

こんな感じで、同じソースコードであったとしても、使用するターミナルによっては出力結果が異なる可能性があるので注意してください。

スポンサーリンク

もっと細かく色の指定を行う方法

使用するターミナルによっては、もっと細かく色の指定を行うこともできます。

細かく色を指定して色の変更を行う際には、エスケープシーケンスとして \x1b[38;5;<color_number>m\x1b[48;5;<color_number>m の出力を行います。

前者では文字の色の変更、後者では背景の色の変更を行うことができます。また、<color_number> には 0255 の色番号を指定します。

色番号に応じた色がどのように変化するかについては、<code> に指定可能な数値の調べ方 で紹介した方法と同様に、実際に出力を行なってみると分かりやすいと思います。

下記は、\x1b[38;5;<color_number>m<color_number> 部分を 0255 の間で変化させながら文字を出力するソースコードになります。

文字の色の変更結果の表示
#include <stdio.h>

int main(void) {

    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < 16; j++) {
            printf("\x1b[38;5;%dm %03d \x1b[0m", i * 16 + j, i * 16 + j);
        }
        printf("\n");
    }
}

私の環境での実行結果は下の図のようになりました。

細かく文字色の指定を行なった際の出力結果

さらに下記は、\x1b[48;5;<color_number>m<color_number> 部分を 0255 の間で変化させながら文字を出力するソースコードになります。

背景色の変更結果の表示
#include <stdio.h>

int main(void) {

    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < 16; j++) {
            printf("\x1b[48;5;%dm %03d \x1b[0m", i * 16 + j, i * 16 + j);
        }
        printf("\n");
    }
}

私の環境での実行結果は下の図のようになりました。

細かく背景色の指定を行なった際の出力結果

<code> に指定可能な数値の調べ方 で紹介した出力結果に比べると、表現できる色の幅が広がっていることが確認できると思います。

ただし、前述の通り使用するターミナルによって \x1b[38;5;<color_number>m\x1b[48;5;<color_number>m のエスケープシーケンスに対応していない可能性があるので注意してください。

さて、上記で <color_number> に指定できるのは 0255 のみでしたので、指定できる色の種類は最大 256 であることになります。

それに対して、使用するターミナルによっては、さらにもっと多くの種類の色を指定することも可能です。

具体的には、\x1b[38;2;<r>;<g>;<b>m\x1b[48;2;<r>;<g>;<b>m のエスケープシーケンスを出力することで、前者では文字の色、後者では背景の色を <r><g><b> に応じた色に変更することができます。<r><g><b> には、それぞれ赤色・緑色・青色の輝度値を指定します。

また、<r><g><b> それぞれに対して 0255 の値を指定することができます。なので、256 x 256 x 256 種類の色を表現することができることになります。

輝度値と聞くと難しいかもしれませんが、要は各色の強さを表す値になります。画像の各画素の色も赤色・緑色・青色の輝度値で表現されていたりします。

例えば \x1b[38;2;255;0;0m を出力すれば、以降の文字の色が赤色になりますし、\x1b[48;2;255;255;0m を出力すれば、以降の背景の色が黄色になります。

また、例えば画像を読み込み、画像の各画素の色に合わせて printf での出力文字の色を変更するようにすれば、下の図のような文字列をターミナル上に出力するようなこともできます(出力しているのは の文字のみで、画像の各画素の色に合わせて の色を変更するようにしています)。

RGB形式で色を指定した場合の出力結果(VSCode)

ただ、上の図の出力結果は VSCode 付属のターミナルのものであり、同じプログラムを使用しても、Mac 標準のターミナルの場合は下の図のように表示されてしまいました…。

RGB形式で色を指定した場合の出力結果(ターミナル)

要は、Mac の標準ターミナルでは \x1b[38;2;<r>;<g>;<b>m のエスケープシーケンスに対応していないということです。なので出力結果がデタラメなものになってしまいます。

この形式の色指定は、輝度値やカラーコードの扱いに慣れている方には一番馴染み深い指定方法になると思いますが、残念ながら、少なくとも Mac の標準ターミナルでは対応していないようです(もしかしたらもっと他に良いエスケープシーケンスがあるのかもしれないですが…)。

こんな感じで、使用するターミナルによってはエスケープシーケンスに対応していないものがありますので注意してください。

参考サイト

このページを作成するにあたり、下記のページを参考にさせていただきました。

まとめ

このページでは、printf で「文字の色や背景色を変更する」方法について解説しました!

printf で \x1b[<code>m のエスケープシーケンスを出力することで、それ以降の出力結果の色等を変更することができます。例えば <code>31 を指定すれば、文字の色を赤に変更できます。

具体的に <code> に指定可能な値や、その値によって出力結果がどのように変化するかは <code> に指定可能な数値の調べ方 で紹介した方法で実際に調べてみていただければと思います。

また、プログラムの途中で色を元に戻したい場合はリセットを行う必要があります。リセットは、例えば \x1b[0m のエスケープシーケンスを出力することで行うことができます。

また、使用するターミナルによっては もっと細かく色の指定を行う方法 で紹介した下記のエスケープシーケンスを指定することで、色をもっと細かく指定することも可能です。

  • \x1b[38;5;<color_number>m
  • \x1b[48;5;<color_number>m
  • \x1b[38;2;<r>;<g>;<b>m
  • \x1b[48;2;<r>;<g>;<b>m

ただし、ターミナルによってはエスケープシーケンスが対応していない、色合いが異なるなどの違いも発生するので注意してください。

とりあえず printf で文字の色や背景の色を変更できれば実現できるプログラムの幅も広がりますので、ぜひ利用してみてください!

オススメの参考書(PR)

C言語学習中だけど分からないことが多くて挫折しそう...という方には、下記の「スッキリわかるC言語入門」がオススメです!

まず学習を進める上で、参考書は2冊持っておくことをオススメします。この理由は下記の2つです。

  • 参考書によって、解説の仕方は異なる
  • 読み手によって、理解しやすい解説の仕方は異なる

ある人の説明聞いても理解できなかったけど、他の人からちょっと違った観点での説明を聞いて「あー、そういうことね!」って簡単に理解できた経験をお持ちの方も多いのではないでしょうか?

それと同じで、1冊の参考書を読んで理解できない事も、他の参考書とは異なる内容の解説を読むことで理解できる可能性があります。

なので、参考書は2冊持っておいた方が学習時に挫折しにくいというのが私の考えです。

特に上記の「スッキリわかるC言語入門」は、他の参考書とは違った切り口での解説が豊富で、他の参考書で理解できなかった内容に対して違った観点での解説を読むことができ、オススメです。題名の通り「なぜそうなるのか?」がスッキリ理解できるような解説内容にもなっており、C言語入門書としてもかなり分かりやすい参考書だと思います。

もちろんネット等でも色んな観点からの解説を読むことが出来ますので、分からない点は別の人・別の参考書の解説を読んで解決していきましょう!もちろん私のサイトも参考にしていただけると嬉しいです!

入門用のオススメ参考書は下記ページでも紹介していますので、こちらも是非参考にしていただければと思います。

https://daeudaeu.com/c_reference_book/

同じカテゴリのページ一覧を表示

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です