ファイルのテキストの中の文字列はどのような型で宣言されているか、
わかる人がいたら教えてください。
 例えば、fopenでFILE宣言しているstreamにおとして、streamの中から1文字を
とる時にfgetcでintのiに入れますよね。この文字をprintするときに%cとやったら
ここで、型がint→charに変わってちゃんと表示されるのはわかるのですけれど、SJISの日本語2バイトからなっている物ではそれぞれの情報をi[0],i[1]に格納してそれぞれをchar型に変換して連続して表示しなければならない。そうすると、intが16ビットだとすると(32ビットの時もあるらしいので)、テキストファイルでは1文字が16ビット連続で表されているはずなのに、streamから16bitずつひっぱて8bitに直してから、また、連続して表示しなければ、出力ができないんですよ。
 これはテキストファイルからstramのときに1文字の1byteにまた1byteが自動的に
てういているように感じるのですけれど、もし、わかる人がいたら教えてください。説明がわかりずらいですけれど。。。。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

ファイルの中身はどんな場合でもただの1byte単位の数字の羅列にすぎません。


そこには型の情報はありません。
2byteで一文字というのは読み出して使うプログラム側で管理する必要があります。

根本的な勘違いは、fgetc の働きにあります。
fgetc はファイルから 1byte(1文字ではない)を取り出すという関数でしかありません。2byteとってることはしないと言うことです。

戻り値はintですが、この時点ではまだ「文字」として扱っているわけではありません。
int(これが2byteでも4byteでも同じで)の変数の中に1byteの数字を入れているだけです。
だから、charに型キャストするんです。このキャストで上位バイトは捨てられます。

マルチバイト文字を扱うのでしたら、fgetwcという関数があります。こちらは1文字拾ってきてくれます。
(返す値は wint_t 型になります)
    • good
    • 0
この回答へのお礼

よくわかりました。fgetwcについても勉強させてもらいます。(m__m)
ありがとうございました。

お礼日時:2001/03/14 12:50

まず、fgetcで読み出すのは、ファイルの中に存在しているデータの1バイトのみです。


2バイト文字が入っていても、1バイトのデータしか読み出しません。
従って、出力される(ここでの場合変数i)データは1バイト分のデータのみです。出力が16bit(2バイト)であっても2バイトの情報は読み出されません。
関数仕様をもっと理解されて方がよろしいかと思います。
    • good
    • 0
この回答へのお礼

 もっと勉強します。どうもありがとうございました。

お礼日時:2001/03/14 12:58

MS-DOSのOS系では通常テキストファイルの英数字文字は1文字を16進2桁で表され、それが間断なく続きます。


日本語などの漢字では英数字分2文字分を使用します。

ところが、C言語の処理系がつくられたころ、日本語は考慮されていませんでした。
(というか、外人が考案したものですから)
ですので、文字をいれるのに都合の良い1Byte変数を用意したわけです。
それがおわかりのようにchar型ですね。
そこで、日本語を使用するために2Byte文字使用するわけですが、
ここで、落とし穴があります。

** 重要 **
使用するOSによって、2Byte文字、つまり、int型の内容が1Byte区切りで反転しているものがあるのです。
いわゆるリトルエンディアンというもので、
これはintel系のマシンで採用されています。
具体的にいうと、int型は16bitで、16進数値が2文字入ります。
そこで、1234Hというものを表現するとき、1Byte目に34H、2Byte目に12Hをセットしなくてはなりません。
ところが、文字コードの場合、1Byte目に12H、2Byte目に34Hと表現しなくてはならないのです。

まとめると、テキストをプログラムの数字変数(integer)に2byteずつセットすると、必ず1byte毎に反転してしまのです。

たぶん、それが原因の事象だと思います。

尚、intel系はリトルエンディアンといい、反転しないのをビッグエンディアンといいます。
相互に変換することをエンディアン変換といいます。

それと、intが16bitしかつかわないのは16bitパソコンの名残であり、unix系など32bitOSはintが32bit使用します。
    • good
    • 0
この回答へのお礼

質問が悪かったです。聞きたいことが違っていましたけれど、知らない貴重な情報提供と協力してもらえたことに感謝します。ありがとうございました。

お礼日時:2001/03/14 12:54

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

Qchar型+char型ってint型? if(char型==int型)?

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょうか。)


if(a[0]==i) /* char型とint型の比較(?) */
の部分では、左辺はchar型、右辺はint型ですが、このように型の違う変数を比較しても文法上構わないのでしょうか。
(私は、「比較は必ず型の同じもの同士でしかできない」と思っていました。)
左辺はchar型のように見えて、じつはint型ですか。


#include <stdio.h>
int main(void)
{
char a[4];
int i=77;
printf("sizeof(int)は%d\n", sizeof(int));
printf("sizeof(char)は%d\n", sizeof(char));
printf("sizeof('M')は%d\n", sizeof('M'));
printf("sizeof(a[0])は%d\n", sizeof(a[0]));

a[0]='M';
a[1]=7+6;
a[2]=a[0]+a[1];
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
printf("sizeof(+a[0])=%d\n", sizeof(+a[0]));

if(a[0]==i) /* char型とint型の比較(?) */
puts("a[0]==i");
else
puts("a[0]!=i");

return(0);
}

ちなみにワーニングもエラーもなんにもでません。

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょう...続きを読む

Aベストアンサー

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優先順位の低い演算子を含む式を裸で渡すことはませんが、( ) で囲めばどんな式でも書けるわけです。

後置式は「配列構文によるアドレス参照式」や「関数呼び出し式」、「メンバ参照式」「後置型インクリメント/デクリメント式」です。
なので、
> sizeof(a[0])
> と書いたら、[ ] という演算子は2項演算子だから、a[0]は単項式になっていない
は、わざわざ ( ) で囲まず sizeof a[0] と書いても、正しい単項式なので問題ありません。
(これらの演算子は、全て sizeof より優先順位が上になっています。)

先に ++ も単項式を取る、ということを書きましたが、++ だって
  ++*(p + n)
のような記述が通るのだから、sizeof でも問題がなくて当然です。

また、例えば ++ では「オペランドは左辺値でなければならない」という原則があり、左辺値でない式に ++ を適用するとコンパイルエラーが発生します。
しかし、sizeof に「オペランドはオブジェクトでなければならない」などという原則を聞いたことがありません。
無論コンパイルエラーも起きませんし、期待通りに式の値のサイズが返ります。
「式の値のサイズ」というのはコンパイル時に判明しているものなので、取得できて当然といえば当然ですが、これがCで定められた仕様かどうかというのは残念ながら見つけることはできませんでした。
ただし、質問にあるような sizeof の文法は全て正しく、警告が出ないのは仕様通りだというのは間違いありません。

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優...続きを読む

Qint main(int argc, char* argv[]) についての質問

こんにちは.つね日ごろ思っている質問させてください.
Cの参考書には,
(1)
void main(void)
{
}

(2)
int main(int argc, char* argv[])
{
return 0;
}
の2つのパターンが記載されていますが,
どういう違いがあるのでしょうか?

(1)の場合main関数は,型を持たず,引数も持たない.
※Turbo Cなどのコンパイラーでは,
return文がないと警告出ます.
(2)の場合は,int 型をかえし,引数はint型 変数と char型ポインタ配列(?)
を指定している.
といったくらいしか分かりません.

(2)に関してもう少し述べれば,
コマンドラインからファイルを指定し,実行することが
できると勉強した記憶があるのですが,
理解があいまいです.

特に(2)の場合のmain関数の意味と,その使い方について
アドバイスお願い致します.

Aベストアンサー

> (1)
> void main(void)
  ...
> (2)
> int main(int argc, char* argv[])
  ...
> の2つのパターンが記載されていますが,どういう違いがあるのでしょうか?

(1) は、間違いです。少なくとも ANSI-C の規格に合致していません。

main() は、特別な関数で、ANSI-C の規格では以下の三通りのうちのどれか
でなくてはいけない、と定められています。

int main(void)
int main(int argc, char *argv[]);
int main(int argc, char *argv[], char *envp[]);

因みに三番目の形式では、三つ目の引数には環境変数が入ります。
以下のようなコードで確認ができます。

int main(int argc, char *argv[], char *envp[])
{
  int i = 0;
  while (envp[i]) {
    printf("envp[%d] = '%s'\n", i, envp[i]);
    ++i;
  }
  return 0;
}


> ※Turbo Cなどのコンパイラーでは,return文がないと警告出ます

Turbo C は、規格に厳格なのでしょう。返り値が void なのはおかしいので、
int だとみなすよ、という警告も出てるはず。で、int が帰り値だとみなし
ているので return が無いと、返り値が不定になるよ、と警告を出している
のでしょう。

> (1)
> void main(void)
  ...
> (2)
> int main(int argc, char* argv[])
  ...
> の2つのパターンが記載されていますが,どういう違いがあるのでしょうか?

(1) は、間違いです。少なくとも ANSI-C の規格に合致していません。

main() は、特別な関数で、ANSI-C の規格では以下の三通りのうちのどれか
でなくてはいけない、と定められています。

int main(void)
int main(int argc, char *argv[]);
int main(int argc, char *argv[], char *envp[]);

因みに三番目の形式では、三...続きを読む

Q「void ( *signal(int sig, void (*func)(int)) ) (int)」の (int)

signal関数の書式についてですが、

  void ( *signal(int sig, void (*func)(int)) ) (int);

最後に付く(int)は一体何でしょうか?
このような関数の書式ははじめて見ました。
UNIX系の何かでしょうか。
回答よろしくお願いします。

Aベストアンサー

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t sighandler);
より後半部分のtypedefを置き換えると
sighandler_t signal(int signum, void (*sighandler)(int));
つぎに戻り値の部分のtypedefを置き換えると
void (*signal(int signum, void (*sighandler)(int)))(int);
となります。
(
sighandler_t signal(int signum, void (*sighandler)(int));
の「signal(int signum, void (*sighandler)(int))」をAと置き換えて
sighandler_t A;
からtypedefを置き換えると
void (*A)(int);
となり、Aを戻すと
void (*signal(int signum, void (*sighandler)(int)))(int);
となる。
)

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t sighandler);
より後半部分のtypedefを置き換えると
sighandler_t signal(int signum, void (*sighandler)(int));
つぎに戻り値の部分のtypedefを置き換えると
void (*signal(int signum, void (*sighandler)(int)))(int);
となります。
(
sighandler_t signal(int signum, void (*sighandler)(int));
の「signal(int signum, void (*sighandler)(int))」をAと置き換えて
sighandler_t A;
からtypedefを置き換...続きを読む

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

Qvoid **(char や intのアドレス混在)について

printf("%d",voidd[0]);にてほしい値が表示されません。
どうすればいいですか?
よろしくお願いします。
#include<stdio.h>
int main()
{
/*
Calc.StringExpressionGet("1+((2+34)*2-111*77)*5-67*8/90");
Calc.StringExpressionResolve();
Calc.Print();
*/
int num[3];
num[0]=111;
num[1]=222;
num[2]=333;
char str[4]="ABC";
void **voidd;
voidd=new void*[6];
voidd[0]=(void *)&num[0];
voidd[1]=(void *)&str[0];
voidd[2]=(void *)&num[1];
voidd[3]=(void *)&str[1];
voidd[4]=(void *)&num[2];
voidd[5]=(void *)&str[2];
printf("%d",voidd[0]);
getchar();
return 0;
}

printf("%d",voidd[0]);にてほしい値が表示されません。
どうすればいいですか?
よろしくお願いします。
#include<stdio.h>
int main()
{
/*
Calc.StringExpressionGet("1+((2+34)*2-111*77)*5-67*8/90");
Calc.StringExpressionResolve();
Calc.Print();
*/
int num[3];
num[0]=111;
num[1]=222;
num[2]=333;
char str[4]="ABC";
void **voidd;
voidd=new void*[6];
voidd[0]=(void *)&num[0];
voidd[1]=(void *)&str[0];
voidd[2]=(void *)&num[1];
voidd[3]=(void *)&str[1];
voidd[4]=...続きを読む

Aベストアンサー

No.1です。すみません、間違えました。

*(int*)(voidd[0])

です。


人気Q&Aランキング

おすすめ情報