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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C

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

Q&A

4回答

3064閲覧

c言語の基本データ型

mightyMask

総合スコア143

C

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

0グッド

1クリップ

投稿2017/03/01 13:38

編集2022/01/12 10:55

c言語での基本データ型で知りたいことがあります。

#質問1
1.signed long
2.unsigned long
3.signed char
4.unsigned long

私の環境でこの4つの型でシフト演算をし時間を計測したところ、列挙した順に速かったのです。

signed と unsigned ではなぜ計算速度に差が出るのか、そしてなぜ1byteのcharより8byteのlongの方が速いのかということに疑問を抱きました。

8byteの型はメモリを8つ連番で使用していると認識していますが、内部でどのように計算してるかはよく知りませんが、1byteのcharの方が速そうなもんです。

#質問2
私が構想を練っているソフトでは、56byteのデータを扱いたいのですが、intやlongより大きいそのような型を定義することはできますでしょうか。

具体的には、将棋のAIを開発しようと思っていて、局面を表すデータ型として使用しようと思っています。上の方法が無理だったり、できたとしてもあまり実用的でないのなら普通に構造体と配列を使いますが、知識として知っておきたいというのもあります。

使用しているコンパイラはgcc ver4.2.1です。

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

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

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

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

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

yohhoy

2017/03/01 14:40

(もしわかれば)動作環境のCPUアーキテクチャを追記ください。また「56byteのデータを扱いたい」とは、56byte=448bit長の一つのデータ型を使ってビットシフト演算をしたいという意味でしょうか?
guest

回答4

0

signed/unsignedの違いについてコメントします。

失礼ながら測定誤差の可能性はないでしょうか?

きちんとデータシートを見たわけではないので単なる想像でしかありませんがこの2種類の命令は大抵のプロセッサで同一の性能ではないかなぁと思います。

自分のPCはIA64ですがgccで最適化なしでコンパイルし、アセンブラソースで期待外の最適化が行われていないことを確認した上で100M回のシフトによる測定をsigned/unsignedで交互に行い、それを100回やって平均・標準偏差をみると以下のようになりました。(clock関数による結果)

平均 標準偏差
194.70 9.96 singed
193.73 10.14 unsigned

この結果から自分は「どちらが早いとは言えない」と思いました。こんなことをしなくても本来はプロセッサのデータシートを調べるべきなのでしょうが・・・

もし上記よりおおざっぱな測定をしていたとしたら、本当に「違うかどうか」より注意深く測定して「違う」という確証を得てから「なぜ違うか」を考えた方がよいのではないかと思います。もし充分な測定を行った上での質問だったとしたら大変失礼なコメントになってしまいますが、その際はご容赦を。

(なお、char/longについてはChironianさんがおっしゃるように違いがあっても不思議ではないと思いました。)

投稿2017/03/01 15:13

編集2017/03/03 02:29
KSwordOfHaste

総合スコア18392

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

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

0

アーキテクチャがRISCかCISCか、また、CISCでも最近のCPUは内部がRISCなのでCPUが何かによって違いが出ると思います。

ひとまず、機械語レベルでの違いを見てみました。環境はmacOS SierraでCore i7(x86-64)です。

C

1signed char sc(signed char x) 2{ 3 return x >> 1; 4} 5unsigned char uc(unsigned char x) 6{ 7 return x >> 1; 8} 9signed long sl(signed long x) 10{ 11 return x >> 1; 12} 13unsigned long ul(unsigned long x) 14{ 15 return x >> 1; 16}

を、gcc-6(GCC 6.3.0)で-O0(最適化無し)でコンパイルし、gobjdumpで逆アセンブリした結果は下記になります。

0000000100000dd8 <_sc>: 100000dd8: 55 push %rbp 100000dd9: 48 89 e5 mov %rsp,%rbp 100000ddc: 89 f8 mov %edi,%eax 100000dde: 88 45 fc mov %al,-0x4(%rbp) 100000de1: 0f b6 45 fc movzbl -0x4(%rbp),%eax 100000de5: d0 f8 sar %al 100000de7: 5d pop %rbp 100000de8: c3 retq 0000000100000de9 <_uc>: 100000de9: 55 push %rbp 100000dea: 48 89 e5 mov %rsp,%rbp 100000ded: 89 f8 mov %edi,%eax 100000def: 88 45 fc mov %al,-0x4(%rbp) 100000df2: 0f b6 45 fc movzbl -0x4(%rbp),%eax 100000df6: d0 e8 shr %al 100000df8: 5d pop %rbp 100000df9: c3 retq 0000000100000dfa <_sl>: 100000dfa: 55 push %rbp 100000dfb: 48 89 e5 mov %rsp,%rbp 100000dfe: 48 89 7d f8 mov %rdi,-0x8(%rbp) 100000e02: 48 8b 45 f8 mov -0x8(%rbp),%rax 100000e06: 48 d1 f8 sar %rax 100000e09: 5d pop %rbp 100000e0a: c3 retq 0000000100000e0b <_ul>: 100000e0b: 55 push %rbp 100000e0c: 48 89 e5 mov %rsp,%rbp 100000e0f: 48 89 7d f8 mov %rdi,-0x8(%rbp) 100000e13: 48 8b 45 f8 mov -0x8(%rbp),%rax 100000e17: 48 d1 e8 shr %rax 100000e1a: 5d pop %rbp 100000e1b: c3 retq

charの方が命令が多いのがわかると思います。そもそもC言語では、int以下の大きさの整数型を演算する場合はint型に変換してから演算します。最適化せずにバカ正直に処理した場合、int型への変換分だけ必ず遅くなります。signedとunsignedの違いはsarshrの違いだけですが、CPUによって異なると思うのでなんとも言えません。x86-64では1命令=1クロックとは限らないからです。

ただし、これを-O2で最適化するとまた変わってきます。

0000000100000e70 <_sc>: 100000e70: 89 f8 mov %edi,%eax 100000e72: d0 f8 sar %al 100000e74: c3 retq 100000e75: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1) 100000e7c: 00 00 00 00 0000000100000e80 <_uc>: 100000e80: 89 f8 mov %edi,%eax 100000e82: d0 e8 shr %al 100000e84: c3 retq 100000e85: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1) 100000e8c: 00 00 00 00 0000000100000e90 <_sl>: 100000e90: 48 89 f8 mov %rdi,%rax 100000e93: 48 d1 f8 sar %rax 100000e96: c3 retq 100000e97: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 100000e9e: 00 00 0000000100000ea0 <_ul>: 100000ea0: 48 89 f8 mov %rdi,%rax 100000ea3: 48 d1 e8 shr %rax 100000ea6: c3 retq

retqまでの処理は全て同じです。nopwはレジスタの後処理らしいですが、x86-64にそこまで詳しくないので、どう影響しているかまではよくわかりせん。

投稿2017/03/05 01:09

raccy

総合スコア21733

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

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

0

こんにちは。

signed と unsigned ではなぜ計算速度に差が出るのか、

不思議ですね。お使いのCPUがsignedのシフト命令を持っているけどunsignedのシフト命令を持っていない時は有り得そうです。右シフトについてはsignedは符号拡張し、unsignedは符号ビットに0を入れます。通常はどちらも1命令で終わります。

そしてなぜ1byteのcharより8byteのlongの方が速いのかということに疑問を抱きました。

例えば、64ビットCPUならlong処理は1命令で済みます。
しかし、1バイト処理する場合、longに対してシフトして目的の1バイト以外の部分を元の値にしたlongへ組み立ててストアするので手間がかかるケースが多いです。

私が構想を練っているソフトでは、56byteのデータを扱いたいのですが、intやlongより大きいそのような型を定義することはできますでしょうか。

構造体を使えば良いと思います。

投稿2017/03/01 14:07

Chironian

総合スコア23272

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

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

mightyMask

2017/03/01 14:45

つまり64bitCPUを使用している場合、longを使う場合もintを使う場合もメモリの使用量は変わらないのでしょうか?
Chironian

2017/03/01 15:22

int型はその処理系が最も得意とするサイズです。ですので、32ビット処理より64ビット処理の方が得意なCPUならその通りと思います。 ただ、int型を64ビットで使うと大きすぎる場合の方が多いと思います。CPUメーカさんもその辺は考慮してCPUを設計てしいるのではないでしょうか? つまり、アドレス・バス幅は64ビットでデータ・バス幅は32ビットに最適化しているのではないかと思います。 内部レジスタはアドレス処理を考慮すると64ビット幅あるでしょう。それを分割して32ビット x 2のモードでも使えるようにして32ビット処理も速度を落とさないようにしているだろうと思います。
guest

0

質問1について、 gcc を使っているのであれば、
gcc -S source.c の様に -S オプションを付けてコンパイルすると、
source.s というアセンブラ言語の中間ソースが出力されます。

その、source.s の中を見て、アセンブラの命令を調べれば、
具体的に何をやっているか分かります。

質問2については、昔自分も仕事で大きな数字を使う必要があり、
コンパイル時に決定する必要はありますが、いくらでも大きな整数
を扱える処理を作った事があります。

変数の格納には、構造体を使いました。

投稿2017/03/02 13:57

ShinyaAnan

総合スコア241

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問