Linux講座にようこそ。このページは「C言語プログラミング入門 - 第14章.ライブラリ関数 - その他のライブラリ」です。

C言語プログラミング入門

14. ライブラリ関数(34/36) - その他のライブラリ(2/4)

14.46 デバッグ支援

14.46.1 assert関数

assert関数はプログラムのデバッグを支援するためのものです。具体的には引数の値が偽(0)の場合、標準エラー出力にメッセージを出力した後、abort関数を呼び出してプロセスを異常終了します。なお、ヘッダファイルassert.hのインクルード前に、NDEBUGマクロが定義されていた場合はassert関数は何の動作も行いません。

assert関数はマクロとして定義されていますが、ここでは関数と記述します。

【表14-8-2】 assert関数
形式#include <assert.h>
void assert(scalar expression);
返り値ありません。
引数
scalar expression
デバッグのための式を指定します。

14.46.2 例題

実行時引数で指定したファイルの内容を標準出力に出力します。ただし、指定したファイルのオープンに失敗した場合はassert関数により異常終了します。

  1. #include <stdio.h>
  2. /* #define NDEBUG */
  3. #include <assert.h>
  4.  
  5. int main(int argc, char **argv)
  6. {
  7.     FILE    *fp;
  8.     int     one_char;
  9.  
  10.     if(argc == 2)
  11.     {
  12.         fp = fopen(*(argv + 1), "r");
  13.         /* オープン出来なかった場合は、異常終了 */
  14.         assert(fp == NULL ? 0 : 1);
  15.  
  16.         /* ファイルから1文字ずつ入力 */
  17.         while((one_char = fgetc(fp)) != EOF)
  18.         {
  19.             putchar(one_char);
  20.         }
  21.  
  22.         fclose(fp);
  23.     }
  24.     else
  25.     {
  26.         /* 実行時引数が不当 */
  27.         printf("実行時引数が不当です。\n");
  28.         return 1;
  29.     }
  30.  
  31.     return 0;
  32. }
$ ls /etc/issue aaa.txt
ls: cannot access aaa.txt: そのようなファイルやディレクトリはありません
/etc/issue
$
$ ./ex14_8_1.prg /etc/issue
Fedora release 10 (Cambridge)
Kernel \r on an \m (\l)

$
$ ./ex14_8_1.prg aaa.txt
ex14_8_1.prg: ex14_8_1.c:14: main: Assertion `fp == ((void *)0) ? 0 : 1' failed.
アボートしました
$
2行目
NDEBUGマクロ定義をコメントにしていますのでassert関数は有効になります。(コメントを取るとassert関数は無効になります)
3行目
assert関数を使いますのでassert.hファイルを取り込みます。
14行目
ファイルポインタ(fp)がNULLの場合、assert関数により異常終了します。

14.47 ロケール情報の取得と設定

ロケール(locale)はメッセージ出力に使用する言語や文字集合および、表記に関する慣習といったような言語や文化ルールの集合です。プログラムをいろいろな国や文化に対応可能とするには、ロケールに応じて適切な動作ができるように作成しなければなりません。

14.47.1 localeconv関数

localeconv関数は現在のロケールの数値に関する書式情報を格納してあるlconv構造体へのポインタを取得します。lconv構造体はロケール・カテゴリのLC_NUMERIC(数値情報)と、LC_MONETARY(通貨情報)に関連する値を保持しています。

【表14-8-3】 localeconv関数
形式#include <locale.h>
struct lconv *localeconv(void);
返り値lconv構造体へのポインタを返します。
引数 ありません。

lconv構造体の内容は次の通りです。この構造体はヘッダファイルのlocale.hに宣言されています。なお、下表の最初から3つは通貨以外の数値情報で、4つ目以降は通貨情報です。

【表14-8-4】 lconv構造体のメンバー
メンバー名型名内容
decimal_pointchar *小数点を表す文字です。
thousands_sepchar *整数部の区切り文字です。
groupingchar *区切り文字で区切る整数部の桁数です。
int_curr_symbolchar *最初の三つの文字はISO 4217の通貨記号、四番目の文字は区切り文字、五番目は半角スペースです。
currency_symbolchar *通貨記号です。
mon_decimal_pointchar *小数点を表す文字です。
mon_thousands_sepchar *thousands_sepと同じです。
mon_groupingchar *groupingと同じです。
positive_signchar *正の値を表す符号です。
negative_signchar *負の値を表す符号です。
int_frac_digitschar国際的な小数部の数字です。
frac_digitscharローカルな小数部の数字です。
p_cs_precedeschar正の値の前に通貨記号を置く場合は1、後ろに置く場合は0です。
p_sep_by_spacechar正の値と通貨記号の間にスペースを入れる場合は1です。
n_cs_precedeschar負の値の前に通貨記号を置く場合は1、後ろに置く場合は0です。
n_sep_by_spacechar負の値と通貨記号の間にスペースを入れる場合は1です。
p_sign_posnchar正の値に対して、値と通貨記号を括弧で囲む場合は0、符号を値と通貨記号の前に置く場合は1、符号を値と通貨記号の後に置く場合は2、符号を通貨記号の直後に置く場合は3、符号を通貨記号の直前に置く場合は4です。
n_sign_posnchar負の値に対して、値と通貨記号を括弧で囲む場合は0、符号を値と通貨記号の前に置く場合は1、符号を値と通貨記号の後に置く場合は2、符号を通貨記号の直後に置く場合は3、符号を通貨記号の直前に置く場合は4です。

14.47.2 setlocale関数

setlocale関数はロケールの設定と取得を行います。

【表14-8-5】 setlocale関数
形式#include <locale.h>
char *setlocale(int category, const char *locale);
返り値設定したロケールに対応する内部文字列を返します。エラーの場合はNULLを返します。
引数
int category
カレントロケール(現在設定してあるロケール)に設定するロケール・カテゴリを指定します。指定できる値は表14-8-6の通りです。
const char *locale
設定するロケールの名前を指定します。ヌル文字("")を指定した場合は、環境変数に設定されているロケール名を使用しますが、処理系により環境変数名等は異なります。setlocale関数の返り値を指定することもできます。また、NULLを指定した場合は設定は行わずに、カレントロケールを返り値として返します。

第1引数のcategoryには下表の値を指定できます。

【表14-8-6】 ロケール・カテゴリ一覧
カテゴリ名内容
LC_ALL全てのカテゴリです。
LC_COLLATE正規表現のマッチング(範囲表現と等価クラスのマッチングを決定する)と文字列の照合です。
LC_CTYPE正規表現のマッチング、文字の分類、文字の変換、大文字小文字比較、ワイド文字関数です。
LC_MESSAGES地域化可能な自然言語メッセージです。
LC_MONETARY通貨の書式です。
LC_NUMERIC数値の書式(小数点や3桁ごとの区切り等)です。
LC_TIME時刻と日付けの書式です。

14.47.3 例題

入力した値をロケールに従い通貨表現形式に編集して標準出力に出力します。なお、ここで使用しているstrfmon関数はANSI Cの標準ライブラリではないため、詳細な説明は省略します。

  1. #include <stdio.h>
  2. #include <locale.h>
  3. #include <monetary.h>
  4.  
  5. int main(void)
  6. {
  7.     char    *p_locale;
  8.     char    buff[50];
  9.     double  in_data;
  10.  
  11.     /* ロケールを環境変数から取得して設定 */
  12.     if ((p_locale = setlocale(LC_ALL, "")) == NULL) {
  13.         fprintf(stderr, "ロケールが設定できませんでした。\n");
  14.         return 1;
  15.     }
  16.     printf("ロケール : %s\n\n", p_locale);
  17.  
  18.     while(1)
  19.     {
  20.         printf("数値を入力してください(0で終了)==> ");
  21.         scanf("%lf", &in_data);
  22.  
  23.         if(in_data != 0.0)
  24.         {
  25.             /* 国内通貨フォーマットに編集 */
  26.             strfmon(buff, sizeof(buff), "%n", in_data);
  27.             printf("%s\n", buff);
  28.         }
  29.         else
  30.         {
  31.             break;
  32.         }
  33.     }
  34.  
  35.     return 0;
  36. }
$ ./ex14_8_2.prg
ロケール : ja_JP.UTF-8 ← 設定したロケールです

数値を入力してください(0で終了)==> 123
¥123
数値を入力してください(0で終了)==> 1234
¥1,234
数値を入力してください(0で終了)==> 1234567890
¥1,234,567,890
数値を入力してください(0で終了)==> -1234567890
¥-1,234,567,890
数値を入力してください(0で終了)==> 0
$
$ export LANG='da_DK' ← LANG環境変数の値をda_DKに変更します
$ echo $LANG
da_DK
$ ./ex14_8_2.prg
ロケール : da_DK ← 設定したロケールです

数値を入力してください(0で終了)==> 123
kr 123,00
数値を入力してください(0で終了)==> 1234
kr 1.234,00
数値を入力してください(0で終了)==> 1234567890
kr 1.234.567.890,00
数値を入力してください(0で終了)==> -1234567890
kr -1.234.567.890,00
数値を入力してください(0で終了)==> 0
$
2行目
setlocale関数を使用しますのでlocale.hファイルを取り込みます。
12行目
setlocale関数でロケールを設定します。設定するロケールは環境変数に設定されているものです。
16行目
12行目で設定したロケールを表示します。
26行目
入力した数値をstrfmon関数で現在のロケールの通貨表現形式に編集します。