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

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

ただいまの
回答率

90.32%

  • C

    3998questions

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

c言語の基本データ型

受付中

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 643

mightyMask

score 63

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です。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yohhoy

    2017/03/01 23:40

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

    キャンセル

回答 4

+5

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

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

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

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

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

こんにちは。

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 23:45

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

    キャンセル

  • 2017/03/02 00:22

    int型はその処理系が最も得意とするサイズです。ですので、32ビット処理より64ビット処理の方が得意なCPUならその通りと思います。

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

    キャンセル

+2

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

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

signed char sc(signed char x)
{
    return x >> 1;
}
unsigned char uc(unsigned char x)
{
    return x >> 1;
}
signed long sl(signed long x)
{
    return x >> 1;
}
unsigned long ul(unsigned long x)
{
    return x >> 1;
}

を、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にそこまで詳しくないので、どう影響しているかまではよくわかりせん。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    3998questions

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