• ベストアンサー

ビット幅とその出力について

C言語を習い始めた者ですが、ビット幅とその出力についてわからないことが二つでてきました。以下のソースコードを見てください。 #include <stdio.h> int main(void) { char ss[] = "ABCDEF"; void *vpt; int idt; vpt = ss; idt = * (char *)vpt; printf("char:%x\n", idt); idt = *(int *)vpt; printf("char:%x\n", idt); return 0; } 出力結果は char:41 char:44434241 となります。 一つ目のわからないことは char:41 についてです。私はchar型のビット幅は8ビットで文字ABの16進数を出力すると予想していました。ところが結果は 文字A の16進数の41のみが出力されました。Aの二進数は 1010、 Bの二進数は1011で それぞれ4ビットずつ持っていて合わせて8ビットになるのでそう考えていました。よくわかりませんが結果から、文字一文字に対して8ビットつまり1バイトに相当するのでしょうか? 二つ目は char:44434241 についてです。一つ目の質問に書いた推測が正しければ1文字を1バイトと考えて16進数にすると Aは41 Bは42 Cは43 Dは44 になります。しかしポインタの先頭のアドレスはAになっているはずなのになぜか出力は char:41424344 ではなくchar:44434241になっています。順序が逆になっているのでしょうか? Cをはじめたばかりなので基本的なところがわかっていないかもしれませんが、説明に不足があればつけたしますのでどうかよろしくお願いします。 

質問者が選んだベストアンサー

  • ベストアンサー
  • os6v100i
  • ベストアンサー率44% (16/36)
回答No.3

まず >char ss[] = "ABCDEF"; ですが、これは 'A','B','C','D','E','F','\0' が配列に格納されます。 'A' = 文字Aを表す文字コード = 0x41です。 0x0Aではありませんし、1011という4ビットの数字でもありません。 従って >idt = * (char *)vpt; >printf("char:%x\n", idt); は、ポインタの指す中身をchar(8bit)として取り出して、int(ここでは32bitかな?)に格納し、16進数で表示していますから、41と表示されます。 続いて、 >char:44434241 の件ですが、ご使用の環境はint型が32bitでintelのx86系でしょうか? >idt = *(int *)vpt; でポインタの指す中身を32bitの整数として取り出している訳なんですが intelのx86系のCPUではリトルエンディアンといって、整数の上位と下位を入れ替えてメモリに配置します。 たとえば 0x12345678 という数値はメモリ上 0x78 0x56 0x34 0x12 と配置されます つまり、0x41 0x42 0x43 0x44 と配置されたデータを整数として表現すると0x44434241となってしまうわけです。 エンディアンについて参考URLいれておきます。

参考URL:
http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3
shomarket
質問者

お礼

ウィキベィアでエイディアンについて読みました。初めてエイディアンという言葉を知りました。私のはご指摘いただいたとおりリトルエイディアンでした。なぜ逆になるのかわからなかったのですがエイディアンの機能について参考URLより確認し理解することができました。本当にありがとうございました。

その他の回答 (4)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.5

おそらく他の方が回答されている通りだとは思いますが、処理系不明の状況で勝手に決めつけるのは正しい姿勢とはいえません。 一般論で回答すると... > 私はchar型のビット幅は8ビットで文字ABの16進数を出力すると予想していました。 char型のビット幅は処理系定義です。<limits.h>のCHAR_BITマクロを調べてください。出力された41は'A'の値です。ただし、文字コードがASCIIかどうかは分かりません。シフトJISやEUC-JPかもしれませんし、UTF-8かもしれません。TRONコードかもしれません。もっと別の文字コードの可能性もあります。 > Aの二進数は1010、 Bの二進数は1011で それぞれ4ビットずつ持っていて合わせて8ビットになるのでそう考えていました。 処理系に関わらず、そんなことにはなりません。 > 文字一文字に対して8ビットつまり1バイトに相当するのでしょうか? 'A'や'B'のような基本実行文字集合に属している文字は、1バイトに相当します。ただし、8ビットかどうかは(前述の通り)処理系に依存します。つまり、1バイトが8ビットかどうかは処理系に依存します。 > 一つ目の質問に書いた推測が正しければ1文字を1バイトと考えて16進数にすると Aは41 Bは42 Cは43 Dは44 になります。しかしポインタの先頭のアドレスはAになっているはずなのになぜか出力は char:41424344 ではなくchar:44434241になっています。順序が逆になっているのでしょうか? ある型のポインタを、要求する境界調整が異なる型へのポインタにキャストし、参照外しを行った場合の動作は未定義です。バイトオーダー(エンディアン)云々以前に、まったくデタラメの値だったとしても文句はいえません。

shomarket
質問者

お礼

ありがとうございます。処理系によってそれぞれ違うんですね。 なんとなくわかったような気がします。

  • pyonmae
  • ベストアンサー率64% (40/62)
回答No.4

こんにちは。 詳しいお話は他の回答者さんに倣いますが、単純に char ss[] = "VWXYZ"; とかにしてみると、何か見えてくるのではないでしょうか。

  • ann_dv
  • ベストアンサー率43% (528/1223)
回答No.2

2つ目の質問に関しては、No.1さんの言われる通り、リトルエンディアンだからですが、 1つ目の質問に関しては根本的に16進数とASCIIコードを混同されています。 16進数の値:0xABとABのキャラクターコードは全く別な値です。

参考URL:
http://www9.plala.or.jp/sgwr-t/c_sub/ascii.html
回答No.1

 参考URLみるか"エンディアン"で検索して下さい。

参考URL:
http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3

関連するQ&A

  • C言語

    以下のプログラミングについて。 #include<stdio.h> int main(void) { char ss[6]="ABCDE"; printf("ss[0]=%c\n",ss[0]); printf("ss[1]=%c\n",ss[1]); printf("ss[2]=%c\n",ss[2]); printf("ss[3]=%c\n",ss[3]); printf("ss[4]=%c\n",ss[4]); printf("ss[5]=%c\n",ss[5]); printf("ss=%c\n",ss); return 0; } 以上のプログラミングの出力は、 ss[0]=A ss[1]=B ss[2]=C ss[3]=D ss[4]=E ss=ABCDE となると思うのですが、あってますか? また、 printf("ss[5]=%c\n",ss[5]); は、char文でいうとヌル(ナル)文字の\0の部分に相当すると思うのですが、printf("ss[5]=%c\n",ss[5]);の出力制御はどうなるんですか? ご教授願います。

  • ビット演算について

    以下のプログラムを作成して、int型、char型、long型のAND演算・OR演算の結果の違いを見ました。 実行結果からchar型だけ結果の表示の仕方が他と異なっています。 一般的に、バイト数では、 char(1バイト) < short(2バイト) < int(4バイト) のはずなのに、出力結果は、 char(0xffffffff) > short(0xff) = int(0xff) となっていて、charが一番大きく?、shortとintが同じ結果? のようにみえてしまいよくわかりません。 私は、ビット演算が苦手なので、根本的に考え方が間違っているのかも しれませんが、どうしてこのような出力結果となるのか教えてください。 プログラム #include <stdio.h> #include <stdlib.h> int main() { int xi = 0x7F, yi=0x80; int stri1 = xi&yi; int stri2 = xi|yi; printf("** int **\n"); printf("%p\n",stri1); printf("%p\n\n",stri2); char xc = 0x7F, yc=0x80; char strc1 = xc&yc; char strc2 = xc|yc; printf("** char **\n"); printf("%p\n",strc1); printf("%p\n\n",strc2); short xl = 0x7F, yl=0x80; short strl1 = xl&yl; short strl2 = xl|yl; printf("** short **\n"); printf("%p\n",strl1); printf("%p\n\n",strl2); return(0); } 出力結果 ** int ** 0x0 0xff ** char ** 0x0 0xffffffff ** short ** 0x0 0xff

  • ポインタと出力について

    現在C言語を勉強している者ですが、参考書をもとに自分でソースコードを書いて少し疑問に思った所がありました。以下がそのソースコードです。 #include <stdio.h> int main(void) { int dt = 0x41424344; int *ip; char *cp; ip = &dt; cp = (char *)ip; printf("%x\n", *ip); printf("%x\n", *cp); printf("%x\n", *cp++); printf("%x\n", *cp++); printf("%x\n", *cp++); return 0; } 出力結果は 41424344 44 44 43 42 となります。 私の予想していた結果は 41424344 44 43 42 41 でしたが、結果はなぜか44が二回出力されています。 2番目のprintf("%x\n", *cp); と 3番目のprintf("%x\n", *cp++);は明らかに3番目のprintfが *cp++ で番地が1つ進んでいると思うのですが結果を見る限りでは同じ数字44が出力されています。なぜこうなってしまうのでしょうか? 説明不足でしたらまた追加しますのでどうかよろしくおねがいします。  

  • プログラミング C++

    プログラミングのC言語で入力文字を関数を使ってポインタを使わずに逆順にするプログラムを作りたいのですが、ポインタを使ってならできるのですが、ポインタを使わずにはどのように考えればいいでしょうか?。 #include <string.h> void reverse (char *ss); int main(void) { char ss[14]; gets(ss); reverse(ss); printf("逆順=%s\n",ss); return 0; } void reverse(char *ss) { int a,b,c; b=0; c=strlen(ss)-1; while(b<c){ a=*(ss+b); *(ss+b)=*(ss+c); *(ss+c)=a; b++; c--; } }

  • 配列について

    初歩的な質問ですいませんが、質問よろしくお願いします。 ◎1----------------------------- #include<stdio.h> int main(void) { char ss[10]="AB"; printf("ss=%s\n",ss); return 0; } ------------------------------------ ◎2-------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss[0]='A'; ss[1]='B'; ss[2]=0; printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎3------------------------------- #include<stdio.h> #include<string.h> int main(void) { char ss[10]; strcpy(ss,"AB"); printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎4------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss="AB"; printf("ss=%s\n",ss); return 0; } ---------------------------------- 以上4つのプログラムで、◎2と◎3は正常に動くと理解できたのですが、何故、◎1は正常に動き、◎4は「'const char [3]' から 'char [10]' に変換できません。」といったようなエラーが出てしまうか分かりません。 教えていただければ嬉しいです。

  • int型とchar型について

    C言語初心者です。 よろしくお願いします。 ◎1----------------------- #include<stdio.h> int main(void) { int ss[4]="789"; printf("%c\n",ss[0]); return 0; } --------------------------- ◎2----------------------- #include<stdio.h> int main(void) { int *p; p="789"; printf("%c\n",*p); return 0; } --------------------------- ◎1、◎2の2つのプログラムについて疑問があります。 ◎1の「int ss[4]="789";」と◎2の「int *p;」のintの部分は今まで、何の疑問も抱かず、「char」として入力していました。 そこでchar型は1バイトの整数、int型は4バイトの整数ということで容量が違うだけで、intとしても大丈夫だろうと思ったのですが、 ◎1では、「'initializing' : 'char [4]' から 'int [4]' に変換することはできません。」とエラーが出て、◎2では「'char [4]' から 'int *' に変換することはできません。」とエラーが出ます。 intは文字列は扱えないということなのでしょうか? 以上intだと実行できない理由がわかりません。 初歩的なことですいませんが、教えていただけると嬉しいです。

  • 関数に文字列を渡すことについて

    参考書にあったプログラムなのですが、 ------------------------------------------- #include<stdio.h> void strout(char ss[ ]); int main(void) { char st[ ]="ABCDEF"; strout(st); strout("ABab12"); return 0; } void strout(char ss[ ]) { int i; printf("ss=%s\n",ss); i=0; while(ss[i]){ printf("%X ",ss[i]); ++i; } printf("\n"); } ---------------------------------------------- ------------実行結果--------------- ss=ABCDEF 41 42 43 44 45 46 ss=ABab12 41 42 61 62 31 32 ----------------------------------- 初心者という事で、いろいろと疑問があるのですが、 ◎1「stとして、文字配列をss[ ]に渡すのと、"ABab12"として直接文字列をss[ ]に渡すのはとは、どういうことなのかということ。そしてその時ss[ ]はどうなっているか?」 ◎2「実行結果で、最初のprintfからループさせなくてもss=ABCDEF、ss=ABab12が何故2つとも表示され、2つとも16進数が表示されるのか?」 ◎3「while(ss[i])だけで何故、'\0'でない間ループするという事が出来てしまうのか?」 以上のような疑問があります。 先頭のアドレスを渡すといったような説明はあるのですが、いまひとつ分かりません。 教えていただけると嬉しいです。

  • c言語についての質問です。

    #include<stdio.h> int main(void){ int a; printf("1文字たいぷしてください。\n"); scanf("%d",&a); if(a>=65 && a<=90){ printf("大文字です。\n"); } else if(a>=97 && a<=122){ printf("小文字です。\n"); } else{ printf("大文字でも小文字でもありません\n"); } return 0; } このプログラムは正しくなくて、 intをchar %dを%cにかえなければなりません。 なぜintはダメなんでしょうか? できれば丁寧に教えてください。 お願いします。

  • void型ポインタについて

    -------------------------------- #include<stdio.h> void uni_disp(void *p,int typ); int main() { int idt=123456; double ddt=56.789; char ss[]="abcdef"; uni_disp(&idt,'I'); uni_disp(&ddt,'D'); uni_disp(ss,'S'); uni_disp("STRING",'S'); return 0; } void uni_disp(void *p,int typ) { if(typ=='I'){ printf("%d\n",*(int *)p); } else if(typ=='D'){ printf("%f\n",*(double *)p); } else if(typ=='S'){ printf("%s\n",(char *)p); } } ----------------------------------- 以上のプログラム等で、void型ポインタをint型ポインタ、double型ポインタとみなす場合の、「*(int *)p」や「*(double *)p」の表記がどういう仕組みになっているか分かりません。 「*(int)p」などはエラーが出るのですが、やはり表記の意味を理解していないため何故か分かりません。 「*(int *)p」などの表記を分解して教えていただけると嬉しいです。

  • 不定値の出力について

    #include <stdio.h> int main(void) { /*  */ int x=1, a; /*  */ double y=0, b; /*  */ printf("a = %d\n", a); /*  */ printf("b = %f\n", b); /*  */ printf("x/y = %f\n", x/y); /*  */ printf("y/y = %f\n", y/y); /*  */ return(0); } -------------------------------------------------- このようなプログラムを実行すると、どのような出力結果が期待できるのでしょうか。 int 型と double 型しか用いていませんが、型によって説明が異なるのであれば他の型についても回答お願い致します。 コンパイラや環境によって出力結果が異なるのでしょうか。 具体的な出力結果でなく、どのように処理されるためにどのような出力が期待されるという形でも説明を頂けますでしょうか。 Visual C++ で実行した結果は次のようになりました。 -------------------------------------------------- a = -858993460 b = -92559631349317831000000000000000000000000000000000000000000000.000000 x/y = 1.#INF00 y/y = -1.#IND00 -------------------------------------------------- ご教示いただければ幸いです。