書式付き入出力とストリームエラー
printf族とscanf族による書式付き入出力と,入出力時のエラーについて.
処理付き入出力はおなじみ(?)のprintf族とscanf族である.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
char *str="hoge";
char *str2;
int strnum;
char ch='X';
int a=17;
double b=2.5;
/* printf族は%で始まる変換指定子で書式を設定して出力する.*/
/* %cは文字を出力する */
printf("%%cでの出力\t%c\n",ch);
/* %sは文字列を出力する */
printf("%%sでの出力\t%s\n",str);
/* %dは整数を10進数で出力する*/
printf("%%dでの出力\t%d\n",a);
/* %fは浮動小数点で出力する */
printf("%%fでの出力\t%f\n",b);
/* %gはdouble型の値を普通の形式で出力 */
printf("%%gでの出力\t%g\n",b);
/* %eは倍精度浮動小数点で出力する */
printf("%%eでの出力\t%e\n",b);
/* %oは8進数,%xは16進数で出力する.*/
fprintf(stdout,"%%oでの出力\t%o\t\n%%xでの出力\t%x\n",a,a);
/* sprintfは出力先がchar*なprintf */
str2=malloc(20*sizeof(char));
strnum=sprintf(str2,"sprintfしてみた.%d%s\n",a,str);
for(i=0;i<strnum;i++){
fprintf(stdout,"%c",*(str2+i));
}
printf("\n1234567890\t文字数カウント用\n");
/* 変換指定子の%の直後に数値でフィールド指定子をいれることができる.*/
/* 10文字分のスペースに右詰めで出力 */
printf("%10d\n",a);
/* 10文字分のスペースに左詰めで出力 */
printf("%-10d\n",a);
/* 10文字分のスペースに右詰めで出力.空きスペースは0で埋める */
printf("%010d\n",a);
/* 10文字分のスペースに右詰めで出力.
"."の次の数値は小数点第何位まで出力するかを指定 */
printf("%10.5f\n",b);
/* 10文字分のスペースに右詰めで出力.
"."の次の数値は小数点第何位まで出力するかを指定.
空きスペースは0で埋める */
printf("%010.5f\n",b);
/* *で可変長フィールド幅を指定できる. */
for(i=1;i<=10;i++){
printf("%*s\n",i,str);
}
printf("1234567890\t文字数カウント用\n");
/* 入力を読み込んでaにいれる.
ただし,入力は10で始まる整数でなければならない.
そうでなければ失敗する. */
scanf("10%d",&a);
fprintf(stdout,"%d\n",a);
str=malloc(10*sizeof(char));
/* 入力をよみこんでstrにいれる.
ただし入力のうち4文字目まだしか読みとってもらえない.
5文字目以降は無視される. */
scanf("%4s",str);
fprintf(stdout,"%s\n",str);
exit(0);
}
これを実行すると以下が出力される.
%cでの出力 X
%sでの出力 hoge
%dでの出力 17
%fでの出力 2.500000
%gでの出力 2.5
%eでの出力 2.500000e+00
%oでの出力 21
%xでの出力 11
sprintfしてみた.17hoge
1234567890 文字数カウント用
17
17
0000000017
2.50000
0002.50000
hoge
hoge
hoge
hoge
hoge
hoge
hoge
hoge
hoge
hoge
1234567890 文字数カウント用
10555
555
fuga
fuga
.....なんだかかなりやっつけな感じのコードになってしまった.
ストリームエラーというかエラー処理の話.多く処理はエラー処理を必要とする.エラー処理をするためにはエラー情報が必要だ.そのためにはerrnoを調べる.errnoは皆の人気者で皆がちょっかいをだすので,早いものがちだ.そして素早くerrnoを何かにコピーして自分だけ(誰?)のerrnoを手にいれる.そんな感じだ.例えばprintfで直接errnoを出力しようとしても,そのprintfがerrnoを書き換えるなんてことがある(かも).具体的には以下のようになるだろうか.
#include <stdio.h>
#include <errno.h>
extern int errno;
int main()
{
FILE *file=fopen("/var/log/syslog","rw");
int errcp;
/* fopenに失敗すると,NULLが返され,errnoがセットされる. */
if(file==NULL){
/* すぐにerrnoをコピー. */
errcp=errno;
/* perrorを使用すると,
引数で指定された文字列を追加してエラーメッセージをstderrに出力してくれる.
エラーメッセージはsys_errlist[errno]に入っているものが出力される.
*/
perror("error1")
fprintf(stderr,"error2:\t%s\n",sys_errlist[errcp]);
exit(-1);
/***************************************************************************/
/* 当然ながら,sys_errlistにないエラーメッセージを出したいなら,
自分で実装する必要がある.
例えば以下のように */
/*
errnoのコピーerrcpをチェックしてみる.
errcpがもしEACCES(権限がない)ならstderrにPermission errorと出力 */
/*
if(errcp==EACCES){
fprintf(stderr,"Permission error\n");
exit(-1);
}else{
fprintf(stderr,"Error\n");
}
*/
/***************************************************************************/
}
/* エラーが出なかったら */
fprintf(stdout,"Done.\n");
exit(0);
}
上の例のなかで,自分でerrnoをチェックするパターンはerrnoの値の意味を調べたり,errnoのチェックを書いたりする必要があるので面倒くさい.そういう意味でperrorを使用するとかなり嬉しい.あと,エラー文字列を取得してエラーログを取るには
#include <string.h> strerror(int errnum);やsys_errlist[errno]を使用する.どちらも引数,またはインデクスにエラー番号をいれるとエラーメッセージを取得できる.あとはファイルに書くなりする.

