A=B=C=D=100; のような書き方はどうでしょうか

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
みどり

A=B=C=D=100; のような書き方はどうでしょうか

#1

投稿記事 by みどり » 5年前

C言語のソースコードに
A=B=C=D=100;
のような書き方ありますよね。

コンパイル結果として下記のどれに相当でしょうか。
////////// (1)
A=100;
B=100;
C=100;
D=100;

////////// (2)
D = 100;
C = D;
B = C;
A = B;

(1)のほうが好ましいですが、
(2)には問題二つあります:
一つは頻繁にメモリをアクセスして遅い、
また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。


それでは実際(1)と(2)のどっちでしょうか。

アバター
みけCAT
記事: 6247
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: A=B=C=D=100; のような書き方はどうでしょうか

#2

投稿記事 by みけCAT » 5年前

コンパイラによると思いますが、A,B,C,Dが全てint型の変数であると仮定すると、gcc4.8.1では最適化オプションなし、-O2ともに(2)相当になりました。

実行したコマンド

コード:

YUKI.N>gcc -S -o test.s test.c

YUKI.N>gcc -S -O2 -o test_o2.s test.c
test.c

コード:

int A,B,C,D;

void test1(void) {
	A=B=C=D=100;
}

void test2(void) {
	A=100;
	B=100;
	C=100;
	D=100;
}

void test3(void) {
	D = 100;
	C = D;
	B = C;
	A = B;
}
test.s

コード:

	.file	"test.c"
	.comm	_A, 4, 2
	.comm	_B, 4, 2
	.comm	_C, 4, 2
	.comm	_D, 4, 2
	.text
	.globl	_test1
	.def	_test1;	.scl	2;	.type	32;	.endef
_test1:
LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	movl	$100, _D
	movl	_D, %eax
	movl	%eax, _C
	movl	_C, %eax
	movl	%eax, _B
	movl	_B, %eax
	movl	%eax, _A
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE0:
	.globl	_test2
	.def	_test2;	.scl	2;	.type	32;	.endef
_test2:
LFB1:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	movl	$100, _A
	movl	$100, _B
	movl	$100, _C
	movl	$100, _D
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE1:
	.globl	_test3
	.def	_test3;	.scl	2;	.type	32;	.endef
_test3:
LFB2:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	movl	$100, _D
	movl	_D, %eax
	movl	%eax, _C
	movl	_C, %eax
	movl	%eax, _B
	movl	_B, %eax
	movl	%eax, _A
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE2:
	.ident	"GCC: (GNU) 4.8.1"
test_o2.s

コード:

	.file	"test.c"
	.text
	.p2align 4,,15
	.globl	_test1
	.def	_test1;	.scl	2;	.type	32;	.endef
_test1:
LFB0:
	.cfi_startproc
	movl	$100, _D
	movl	$100, _C
	movl	$100, _B
	movl	$100, _A
	ret
	.cfi_endproc
LFE0:
	.p2align 4,,15
	.globl	_test2
	.def	_test2;	.scl	2;	.type	32;	.endef
_test2:
LFB1:
	.cfi_startproc
	movl	$100, _A
	movl	$100, _B
	movl	$100, _C
	movl	$100, _D
	ret
	.cfi_endproc
LFE1:
	.p2align 4,,15
	.globl	_test3
	.def	_test3;	.scl	2;	.type	32;	.endef
_test3:
LFB2:
	.cfi_startproc
	movl	$100, _D
	movl	$100, _C
	movl	$100, _B
	movl	$100, _A
	ret
	.cfi_endproc
LFE2:
	.comm	_D, 4, 2
	.comm	_C, 4, 2
	.comm	_B, 4, 2
	.comm	_A, 4, 2
	.ident	"GCC: (GNU) 4.8.1"
みどり さんが書きました:また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
ロックなど、他の対策を考えてください。
最後に編集したユーザー みけCAT on 2015年2月14日(土) 10:08 [ 編集 1 回目 ]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
nullptr
記事: 239
登録日時: 8年前

Re: A=B=C=D=100; のような書き方はどうでしょうか

#3

投稿記事 by nullptr » 5年前

D = 100;
C = D;
B = C;
A = B;
です。
一つは頻繁にメモリをアクセスして遅い、
何を以って遅いといえるのでしょうか。実測したのでしょうか。
もし
int A, B, C, D;
だった場合、数値リテラルを代入するのであれば、
A=100;
B=100;
C=100;
D=100;
とした場合より遅いことはまず無いと思います。
ちょっと書き方を変えます。確かに、単純な命令数では多くなることも多いかもしれません。
しかし、レジスタアクセスや1クロックで済む命令などは、昨今では本当に誤差のレベルです。他の要因によってあっさりと逆転してしまうようなほどの軽微なものです。
メモリをアクセスして遅い、と言いますが、大抵のアーキテクチャでレジスタアクセスは1クロックレベルで超高速ですし、整数の変数であればコンパイラ次第でキャッシュを仕込むかもしれません。
コンパイラやコードの状況によっては最適化され、結果的に同じコードになることも多いはずです。「速くなると断言もできないし、遅くなる可能性すらある」ことです。
そのようなことを気にして、1のような定数ハードコーディングを行う事は、返ってプログラムの見通しや保守性を落とす結果を招くことがほとんどです。それでプログラムにバグが生まれれば本末転倒です。開発効率を犠牲にしてまでクロック単位で最適化をする開発など、それこそ天文学などの科学計算の分野か、よほど速度の出ない組み込み開発くらいです。
昔はそれが当たり前な時代もあったでしょうけども、今の時代でそれは稀なことです。
確かに実行コストの高い命令を気にしてコーディングすることはありますが、今回の件は過剰すぎます。最も高速な部類の命令すらネックになるのなら、根本的にそのプログラムの設計が間違っているか、スーパーコンピュータでも買うべきです。

また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
それは全く話の違う問題です。代入の問題ではありません。
もし他のスレッドから値が更新される可能性があるのであれば、排他制御を行えば良いだけの話です。それはマルチスレッドの問題であって、C言語の代入構文のせいではありません。
仮に他のスレッドからアクセスされる可能性があるのであれば、
A=100;
B=100;
C=100;
D=100;
と書いたとしても同様にデータレースの可能性があるからです。

(1)の方が好ましいというのは、勘違い、思い込みかと思われます。もし(1)がマルチスレッドで安全だと思ってコーディングしているのなら、そのコードではスレッドセーフではない可能性が高いです。
 
 
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
?
Is the は :
order C++? ✜
     糸冬   
  ――――――――
  制作・著作 NHK
 
 

みどり

Re: A=B=C=D=100; のような書き方はどうでしょうか

#4

投稿記事 by みどり » 5年前

非常に有益な議論と教授をいただきまして、本当にいい勉強になりました。
これからはアセンブラ言語を勉強して、さらに研究していこうと思います。
皆さん、有難うございました!!

YuO
記事: 941
登録日時: 9年前
住所: 東京都世田谷区

Re: A=B=C=D=100; のような書き方はどうでしょうか

#5

投稿記事 by YuO » 5年前

解決となっていますし,今まで投稿していない人間がしゃしゃり出てきて書くのもなんですが,結論の方向が明後日を向いているような気がしたので……。

みどり さんが書きました:これからはアセンブラ言語を勉強して、さらに研究していこうと思います。
アセンブリ言語の勉強よりも,nullptrさんの投稿 (特に前段) をちゃんと理解した方がよいかと思いますよ。
そもそも,速度が出るようにアセンブリ言語で書こうとすると,対象プロセッサを決定し,そのプロセッサの特性を理解し,各命令がどのようにパイプラインを使うかも知った上で,その時点でのキャッシュがどうなっているかも勘案して実行順序も決めていく必要があります。
8086とかの牧歌的な時代ならクロックの総和である程度速度がわかりましたが,今どきのプロセッサはそう簡単に速度がわかる物ではないです。

また,
みけCAT さんが書きました:
みどり さんが書きました:また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
ロックなど、他の対策を考えてください。
nullptr さんが書きました:
また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
それは全く話の違う問題です。代入の問題ではありません。
もし他のスレッドから値が更新される可能性があるのであれば、排他制御を行えば良いだけの話です。それはマルチスレッドの問題であって、C言語の代入構文のせいではありません。
とお二方ともから指摘されているとおり,スレッド間でのアクセス競合の問題はアセンブリ言語を勉強したところでどうにかなるものではないです。

一応,x86系CPUにおいてはi486からCMPXCHG命令が追加されているので,Compare And Swapによるロックフリーアルゴリズムをこれにより作る,というのはできるかもしれませんが,それらは上位層において隠蔽される (e.g. InterlockedExchange (Windows), atomic_compare_exchange_strong (C11), std::atomic_compare_exchange_strong (C++11) etc.) ので,CPU命令を直接使う必要はないでしょう。

アバター
nullptr
記事: 239
登録日時: 8年前

Re: A=B=C=D=100; のような書き方はどうでしょうか

#6

投稿記事 by nullptr » 5年前

みどり さんが書きました:これからはアセンブラ言語を勉強して、さらに研究していこうと思います。
…どうしてそうなったんでしょう…?

別にアセンブラがやりたいならやめろとは言いませんけど、もしも、アセンブラを自分で書けば速くなると思っているのなら、大間違いです。
気をつけてください。
最後に編集したユーザー nullptr on 2015年2月17日(火) 18:26 [ 編集 4 回目 ]
 
 
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
?
Is the は :
order C++? ✜
     糸冬   
  ――――――――
  制作・著作 NHK
 
 

アバター
みけCAT
記事: 6247
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: A=B=C=D=100; のような書き方はどうでしょうか

#7

投稿記事 by みけCAT » 5年前

ある処理の仕方が遅いかどうかを議論するときは、推測をするだけではなく、
実験をしたりデータシートなどで調べたりしてください。
もちろん実験の結果は環境依存ですが、全く根拠がない推測よりはマシだと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る