質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
機械語

機械語とは、プロセッサが直接解釈・実行できる状態の言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

バイナリ

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Q&A

解決済

4回答

3118閲覧

二進数がどのように処理されるかにおいて。

carnage0216

総合スコア194

機械語

機械語とは、プロセッサが直接解釈・実行できる状態の言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

バイナリ

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

0グッド

2クリップ

投稿2021/07/30 00:19

編集2021/07/30 00:20

char型の配列char a[3] = "ab";(ヌルも含めて)により4バイト([0]〜[3])のデータ 0061006200000000となり、 二進数にすると 01100001(0061(a),1バイト), 00111110 (0062(b),1バイト)、後の48bit(6バイト)は0として 64bitのメモリに二進数として保存されるとして、
仮に2バイトずつ読み込むと 0110000100111110となり、ヘンテコな数字が表示されるように思えるし、 どうやって都合よく6162と表示してくれるのだろうか?と疑問が湧きます。 やはり1バイトずつ読み込んでいるのでしょうか?
(だとしても下に書いたint型のように12345の二進数 11000000111001も1バイトずつ読み込むと、多分12345にはならないと思うという謎がのこります。)
また、
int a = 12345として12345の二進数11000000111001も1バイトずつ読み込むと、多分12345にはならないと思うのですが、どうやって12345と都合よく表示しているのか知りたいです。

もう一つ、
あの、printfの演算子%sや%dで二進数0110001(1)を表示すると、どうなるのでしょうか? ただ、1と表示されるだけでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

amiya

2021/07/30 00:34 編集

あの、64bitpcの1つのメモリは64bitですよね?だとしたら、文字aはint aは1バイトなので、64bit中の1バイト(0x61)を使うのでしょう… - Yahoo!知恵袋 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14246839814?fr=and_other char型において、char型は1バイトしか扱えないためchar = "ab"だと2バイトになってしまうと思うのですが、なぜ扱えるのでしょうか? - Yahoo!知恵袋 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13246867158?fr=and_other 元ネタはこちらです。 やっぱりいつもの人でしたか……。 メチャクチャに改変されているので、補足しておくと 元の話は char a[3] = "ab" //3バイト は、64bitに揃えられた環境では、 メモリ上には、 6162000000000000 の形で配置されるという話です。
Munosuke222

2021/07/30 02:49

https://oshiete.goo.ne.jp/qa/12486889.html もうマルチポストの指摘もあんまり意味ないな。teratailの回答者はどうせやってるって知ってるし、知恵袋の方もやってんなあってバレてきてるし。gooの方くらいか、あんまりバレてないの。
Zuishin

2021/07/30 03:53 編集

> メモリ上には、 6162000000000000 の形で配置されるという話です。 そんな決まりありましたっけ? 616200 の次に char 型の変数がアサインされることは C 言語ではどの処理系でもあり得ないということですか? あと必ず 0 で埋められますか?
amiya

2021/07/30 05:05

元の話が、アライメントの話でしたので。 単体の変数はアライメントされるけど、配列は少なくともその数までは詰めて入れられる。と言う事を言っていたのが元です。 (実装依存なのかもですが……)
Zuishin

2021/07/30 05:24

ikadzuchi さんの回答のコメントに検証結果を上げました。 アライメントを考慮する場合、型のサイズが大きい順(long long → long → int)に並べられ、char は一番最後に詰めて置かれる最適化がされていたように思いますが、これは実装依存であり、どの順に並べても C 言語的には問題ないはずです。 そして定義されていないデータ(この場合は 616200 以降)については、未定義だったように記憶しています。 言語仕様の調査まではしていません。
退会済みユーザー

退会済みユーザー

2021/07/30 05:34 編集

そもそもアライメントって何?ってレベルの人間にする話でもないような。 charの扱いにbit数の話を絡めるのが良くない。 616200以降については、何の保証もありません。
maisumakun

2021/07/30 05:34

構造体のフィールドの順は守らなければならない(ポインタの大小が規定されている)ですが、ローカル変数は最適化で変数ごと吹き飛ばす(あるいはレジスタに割り付けてしまう)ことすら許されている程度に自由です。
退会済みユーザー

退会済みユーザー

2021/07/30 05:41

> char型の配列char a[3] = "ab";(ヌルも含めて)により4バイト([0]〜[3])のデータ 0061006200000000となり まずもう質問がめちゃくちゃすぎる。何を見たデータなのこれ?
Zuishin

2021/07/30 08:02 編集

char の扱いについて、64 ビット幅で読み込まれるという回答を受けての質問だということなので、gcc -S で出力してみたところ、movb が使われていました。 以下のサイトに書いてある通り、b がつくのは 8 ビット幅の命令です。 http://nw.tsuda.ac.jp/lec/x64/ キャッシュやパイプラインなどを考慮に入れなければ、8 ビット幅で読み込むような出力がなされています。 複数の char 型のローカル変数がパディングなしで詰めて並ぶ実装があるというのも、ikadzuchi さんの回答へのコメントで示した通りです。 よって C 言語の角度から見ても、出力されたアセンブリ言語の角度から見ても、char が 64 ビットという証拠はみつけることができませんでした。 ただし、レジスタが 64 ビットならば、メモリではなくレジスタを対象とするなら話が変わってくる可能性があります。 もちろん、この場合配列もアライメントも無関係になります。 結論として、char は 1 バイトと考えればいいし、char[3] は 3 バイトと考えればよくて、この質問者は言うまでもなく普通に C 言語を使うことができている人まで悩むようなややこしいことを言う必要はないということになると思います。 添え字外の要素へのアクセスは未定義なので、何が起きる保証もありません。
episteme

2021/07/30 09:09

論理的思考 および 言語による表現 がとことん苦手なんだろうな...
amiya

2021/07/30 14:15

了解しました。 言いたかったことの骨子は、「(アライメントに関わらず、)1つの配列は連続したアドレスに配置される」と言うことなので、charとかパディングとかの要素は余計でした。
Zuishin

2021/08/01 02:30 編集

この人はアライメントというところまでまだ行ってないと思います。 char が整数型だということを叩き込まれたばかりなので、int 型と混同しているふしがあります。 もしかしたら 0 0 6 1 という 4 バイトになると思っている可能性も低くはないと思っています。 上記推測の参考にした資料 https://teratail.com/questions/351865
guest

回答4

0

ベストアンサー

1バイトずつ読み込むか、4バイトあるいは8バイトずつ読み込むかは、変数(式)の型によります。
なので、

char型の配列char a[3] = "ab";【略】

仮に2バイトずつ読み込むと 0110000100111110となり、ヘンテコな数字が表示されるように思えるし

char a[3] と宣言されているので、2バイトずつではなく、1バイトずつ処理することになります。

int a = 12345として12345の二進数11000000111001も1バイトずつ読み込むと、多分12345にはならないと思うのですが、どうやって12345と都合よく表示しているのか知りたいです。

これはintとして宣言されているので、1バイトずつ読むのではなく、4バイト(あるいは2バイト、8バイト等)ずつ処理します。少なくとも1バイトずつということはありません。

メモリ上では単なるビット列ですが、それをバイト単位あるいは4バイト単位で処理するかは、変数や式の型によって変わります。

投稿2021/07/30 02:59

編集2021/07/30 03:03
ockeghem

総合スコア11705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

carnage0216

2021/07/30 11:35

わかりやすい解説ありがとうございます。 ちなみに、aは16進数で0x61とのことですが、この0xのxとは何を表しているのでしょうか?
carnage0216

2021/07/30 12:04

>> メモリ上では単なるビット列ですが、それをバイト単位あるいは4バイト単位で処理するかは、変数や式の型によって変わります。 ちなみに、64bitpcに変数の値や文字を保存する際も何バイトで保存するかは変数や式の方によって変わるのでしょうか?
ockeghem

2021/07/30 14:45

0xは16進数であることの決まりです。C言語を作った人が16進数は 0x61 のように表現するように決めたのです。xはおそらくHexから来ていると思いますが、0xでなければならない必然性はありません。決めの問題です。 64bitPCの場合、ASCIIの文字は1バイトで表現しますが、漢字などはUTF-16という、2バイトまたは4バイトで表現する方式か、UTF-8という方式で3バイト~4バイトで表現することが多いです。数値はshort、int、longでそれぞれ2バイト、4バイト、8バイトで表現することが多いと思いますが、そうでない場合もあると思います。小数(浮動小数点数)は8バイトで表現する(double)ことが多いです。
carnage0216

2021/07/31 08:26

ありがとうございます。
guest

0

いまいちどこが分かっていないのか分かりませんが…

char型の配列char a[3] = "ab";(ヌルも含めて)により4バイト([0]〜[3])のデータ 0061006200000000となり、

16進数だとして、なりませんね。61620000になります。
下記追記の通り、(「0x」の誤りである)「00」は不要なのでせめて61620000ですし、
また4バイトでなく3バイトなので616200になります。

二進数にすると 01100001(0061(a),1バイト), 00111110 (0062(b),1バイト)、後の48bit(6バイト)は0として 64bitのメモリに二進数として保存されるとして、

0062が16進数だとして、00111110ではなく01100010ですね。あと0062の余計な00が謎です。

仮に2バイトずつ読み込むと 0110000100111110となり、ヘンテコな数字が表示されるように思えるし、

2バイト読めばそうなります。char配列で定義した文字列をshortとして読んだりするとたいていそのようになります。(エンディアンの違いはありますが)

どうやって都合よく6162と表示してくれるのだろうか?と疑問が湧きます。 やはり1バイトずつ読み込んでいるのでしょうか?

1バイトづつ読んでもいいですし、複数バイトまとめて読んでから分割してもいいです。

int a = 12345として12345の二進数11000000111001も1バイトずつ読み込むと、多分12345にはならないと思うのですが、どうやって12345と都合よく表示しているのか知りたいです。

何を疑問に思っているのか分かりません。
1バイトづつ読んで駄目なら2バイトづつなり4バイトづつなりで読めばよいですし、
1バイトづつしか読めなくても(例えば8bitCPUはたいてい1バイトづつしか読めない)、1バイトづつ読んだものを適切に処理して"12345"と表示するプログラムは普通に書けます。

あの、printfの演算子%sや%dで二進数0110001(1)を表示すると、どうなるのでしょうか? ただ、1と表示されるだけでしょうか?

2進数0110001は1ではなく(ASCIIコードで「1」に相当する)49ですね。
その2進数が1バイトで定義されているとして、%dではふつう4バイト読むのでその後の3バイトのメモリに入っている内容によりますが、仮に0なら、「49」と表示されるでしょう。
%sなら少なくとも先頭に「1」が表示され、その後のメモリに入っているデータを\0に当たるまで表示し続けます。


0x61,0x62でした。
この場合でも0x610x62ではなく、0xが消えて61620000となるのは何故でしょうか?

あー…なるほどそこをそう誤解しているわけですね。
「0x」というのは次に続くのが16進数だということを示すためのもので、「0x」自体は16進数の一部ではありません。
「0x61」は「『61』という16進数」を表しています。
「0x61」と「0x62」、すなわちそれぞれ2桁の16進数「61」と「62」を、つなげると4桁の16進数「6162」ができます。これは「0x6162」と書くことができます。

つまり、「0x」を16進数の一部だと誤解した上でそれを「00」と書き間違っていたなら、
"ab"とそれに続く(なぜか1バイトでなく)2バイトのヌルを「0061006200000000」と書いているのは、認識自体は間違っていないわけです。
「0061006200000000」←「0x610x620x000x00」←「0x61620000」


話変わって。
思ったのですが、もしかしてN bit CPUはN bitごとにしかメモリを扱えないと思っていませんか?
ほとんどのCPUは、32bitなら8bit, 16bit, 32bitのように自分のレジスタ幅より狭いbit数のデータをメモリから読めます。
また例えばレジスタ幅32bitで32bitごとにしか読めないCPUがあったとしても、
・読むときは32bitを読んでから適宜シフトして不要な部分を0にする
・書くときは一度読んでから必要な部分を書き換えて書き戻す
とすれば32bit未満のデータも扱えます。確か最初期のARMがそうだったと思います。


あ、今気づいたんですが、

int a = 12345として12345の二進数11000000111001も1バイトずつ読み込むと、多分12345にはならないと思うのですが、どうやって12345と都合よく表示しているのか知りたいです。

この文章はもしや、「数値の12345(=11000000111001)をどう読んでも'1', '2', '3', '4', '5'の文字コードにならないが、どうやって表示しているのか」という質問と解釈すべきだったのでしょうか。
であれば答えは「そう都合よくいかないので頑張って10進変換の面倒なプログラムを書いて表示している」です。
10進数への変換は単純な手法では10で割って商と余りを取る繰り返しでできます。きちんとしたライブラリの数値の10進表示ではおそらくもっと速い方法を使っていると思いますが具体的には知りません。

投稿2021/07/30 00:59

編集2021/07/31 04:08
ikadzuchi

総合スコア3047

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

carnage0216

2021/07/30 01:31

すいません。書き間違えていました。 >> 16進数だとして、なりませんね。61620000になります。 について、0x61,0x62でした。 この場合でも0x610x62ではなく、0xが消えて61620000となるのは何故でしょうか?
episteme

2021/07/30 04:09

> 0x610x62ではなく、0xが消えて61620000となるのは何故でしょうか? なんの話かさっぱりわからん。なんかのコードを実行してそうなったんならそのコードを示せ。
Zuishin

2021/07/30 04:19

こっちにもあったか。 修正依頼にも書きましたが、616200 のあとの 00 は何なんでしょう?
episteme

2021/07/30 04:22

↑文字列の終端文字:'\0'もコミで、ってことじゃね?
Zuishin

2021/07/30 04:28 編集

終端文字まではわかるんですが、"ab" という文字列の 4 バイト目に必ず 0 が入りますか? 元ネタは修正依頼に書いてありますが、もっとたくさんの 0 が入っています。
episteme

2021/07/30 04:34

あー... 64-bit CPU/OS だとメモリも64-bit(8-byte)単位で扱われていると思ってるフシがあります。
Zuishin

2021/07/30 04:44 編集

未定義なので別の環境ではまた別の結果になると思いますが、うちの環境で次のコードを走らせると、61620057 と表示され、61620000 になりませんでした。 #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { char a[3] = "ab"; for (int i = 0; i < 4; i++) { printf("%02x", a[i]); } return 0; }
Zuishin

2021/07/30 04:57 編集

構造体を使った場合、次のコードで 61620063 と表示されました。 同じく未定義ですが、こちらの方が再現しやすいかと思います。 #include <stdio.h> #include <stdlib.h> typedef struct{ char a[3]; char b; } st; int main(int argc, char* argv[]) { st a = { "ab", 'c' }; for (int i = 0; i < 4; i++) { printf("%02x", a.a[i]); } return 0; }
Zuishin

2021/07/30 05:30

もう一つ。616263 と表示されました。 私の環境では char にパディングはありません。 #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { char a = 'a'; char b = 'b'; char c = 'c'; for (int i = 0; i < 3; i++) { printf("%02x", *(&a + i)); } return 0; }
Zuishin

2021/07/31 03:44

> char型の配列char a[3] = "ab";(ヌルも含めて)により4バイト([0]〜[3])のデータ 0061006200000000となり、 > 16進数だとして、なりませんね。61620000になります。 この二つは同じこと(4 バイト)なのに訂正される気配がないので低評価しました。 確かに 1 バイトは通常二桁で書き表しますが、四桁で表してはいけないという決まりもなく、全体で 4 バイトと明記されているため、0061 は 61 と同じ数値と読むことができます。 3 バイトになるのが正しいはずです。
ikadzuchi

2021/07/31 04:09

修正しました。
guest

0

char型の配列char a[3] = "ab";(ヌルも含めて)により4バイト([0]?[3])のデータ

3バイトで[0]~[2]ですね。

0061006200000000となり、

16進数で表現する場合、1バイトは4桁でなく2桁で表現するのが普通です。1バイト8ビットで、16進1桁が4ビットのため。なので、616200 ですね。

二進数にすると 01100001(0061(a),1バイト), 00111110 (0062(b),1バイト)、後の48bit(6バイト)は0として

自分で4バイトと書いていながら「後の48bit(6バイト)」と書いているので自己矛盾しています。
実際は3バイトなので、「後の8bit(1バイト)は0として」ですね。

64bitのメモリに二進数として保存されるとして、

これも間違い。

仮に2バイトずつ読み込むと 0110000100111110となり、

これはさすがに勘違いじゃなくて、タイプミスですかね。0110000101100010 ですね。

ヘンテコな数字が表示されるように思えるし、

文字コードのことを知らない人が、文字コードの数値を見るとヘンテコな数字と思うのは当然でしょう。

どうやって都合よく6162と表示してくれるのだろうか?と疑問が湧きます。

16進表示するプログラムを使って表示するとそう表示されます。

やはり1バイトずつ読み込んでいるのでしょうか?

16進表示の場合は、何バイトずつ読むかは関係ないです。

(だとしても下に書いたint型のように12345の二進数 11000000111001も1バイトずつ読み込むと、多分12345にはならないと思うという謎がのこります。)

int型は4バイトとか8バイトなので、そのバイト数単位で処理する必要があります。

また、int a = 12345として12345の二進数11000000111001も1バイトずつ読み込むと、多分12345にはならないと思うのですが、どうやって12345と都合よく表示しているのか知りたいです。

同上。

もう一つ、

あの、printfの演算子%sや%dで二進数0110001(1)を表示すると、どうなるのでしょうか? ただ、1と表示されるだけでしょうか?

0110001 の後ろの (1) はどういう意図でしょうか?普通は、0110001(2) とか 61(16) とか97(10) のように何進数表現かを書くのですが。
%s は文字列だから関係ないとして、%d だと10進表現で書き出しますし、%c だと文字コードだと見なしてその文字を表示します。

投稿2021/07/30 06:18

otn

総合スコア85766

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

char a[3] だと3バイトですよ

2進数とか16進数とか10進数とは、数値をどう表現するのかってだけの話であって、数値は変わらんです。
10進数の12を2進数で表現すれば、1100 に、16進数だとCとなります
数値が変わるわけじゃないです

投稿2021/07/30 00:28

編集2021/07/30 00:37
y_waiwai

総合スコア88024

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問