ページ 1 / 1
while中のint
Posted: 2010年7月15日(木) 11:38
by 深黒
ループ中に変数を使う際、
int main{
while( ProcessMessage() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ){
int count=0;
・
・
・
}
}
というのと、
int count=0;
int main{
while( ProcessMessage() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ){
・
・
・
}
}
というのと、
int main{
int count=0;
while( ProcessMessage() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ){
・
・
・
}
}
では、どれが一番、メモリの効率?動作の負荷?の効率がいいのでしょうか?
Re:while中のint
Posted: 2010年7月15日(木) 11:49
by だいちゃん
とりあえず2番目のmainの外で宣言する(グローバル変数)は
使わないほうがいいでしょう
自分も研修時代とか学生時代は使ってましたが
これはかなりよくない方法のようです
一般的なのは3番目のやつですが
whileの中でしか使わないのであれば1番目の宣言方法だと
多分メモリの節約?になるかも?
やったことないんで分かりませんが
多分whileを抜けた瞬間その変数は消えると思うんで(ガーベジコレクションとは違うのかな?)
もっと詳しい方よろしくお願いします~m(_ _)m
Re:while中のint
Posted: 2010年7月15日(木) 11:57
by たかぎ
> どれが一番、メモリの効率?動作の負荷?の効率がいいのでしょうか?
プラットフォームとコンパイラ、そしてwhile文の内容によります。
whileの副文で関数(実質的に関数として実装される演算子を含む)の呼び出しを行わず、比較的単純な処理しか行わないのであれば、最初のものが一番効率がよくなる可能性が高いと思います。
Re:while中のint
Posted: 2010年7月15日(木) 12:13
by へろりくしょん
ぶっちゃけどれも同じです。
処理系依存かもしれませんが、私の環境(VC6.0)で厳密に言うと。
メモリ効率はどれも同じです。
動作の負荷? で言うなら、ループの中で毎回0の代入を行う(1)が一番高いです。
2と3は同じです。
という結果ですね。
今時のパソコンなら、この程度の差は1000万回ループを回しても実行速度に0.1秒も差は出ないでしょう。
それよりもっと、構造化を意識して安全で読みやすいコードを書くべきだと思います。
だいちゃんさん
>whileの中でしか使わないのであれば1番目の宣言方法だと
>多分メモリの節約?になるかも?
VC6.0が吐いたコード(混合モードですが)を見たところ、while()文内で宣言されている変数も、
main() 関数突入時にスタックを確保しているようでした。
>多分whileを抜けた瞬間その変数は消えると思うんで(ガーベジコレクションとは違うのかな?)
ちょっと違いますね。 ガーベージコレクションはあくまでも動的に確保された使われないメモリを回収するものです。 スタックの場合は、あらかじめまとまった量が確保されてます。 1Mぐらい?
その確保された領域の中で、ここまで使う。 ここまで使う。 と記憶しておくだけですから。
Re:while中のint
Posted: 2010年7月15日(木) 12:30
by 深黒
皆さん返答ありがとうございました
m(_ _)m
Re:while中のint
Posted: 2010年7月15日(木) 12:47
by ookami
他の方も仰るとおり、ケースバイケースだと思います。
int A;
int main{
int B; // 1
while(なにがし){
int C; // 2
なにがし
} // 3
} // 4
↑ちょっといじりましたが、この場合は...
■作成と破棄のタイミングに注目すると、
A:プログラム起動時に作成され、プログラム終了時に破棄される。
B://1 で作成され、//4で破棄される。
C://2 で作成され、//3で破棄される。※ 作成と破棄が、ループの回数分繰り返される。
Cが、作成と破棄が多いぶん 遅くなるように思われますが、
コンパイラが気を利かせて、無駄な作成と破棄をしないようにしてくれる可能性もあります。
■作成されるメモリ領域に注目すると、
A:ヒープ領域
B,C:スタック領域
http://blog.goo.ne.jp/wildriver_1977/e/ ... b841772f7b
> スタック領域は、領域がそのまま使えるの高速で処理することができる。
> ヒープ領域は、ポインタアドレスから実体を見にいくので、若干速度が遅い。
↑らしいので、Aが遅くなるようにも思われますが、
これも同様で、コンパイラが高速化してくれる気がします。
--
ということで、よく分かりませんね。
結局ケースバイケースなので、私は読みやすさとかで決めちゃいます。
-- 追記
あら、解決してましたね^^; 失礼しました。

Re:while中のint
Posted: 2010年7月15日(木) 13:17
by へろりくしょん
>■作成されるメモリ領域に注目すると、
>A:ヒープ領域
>B,C:スタック領域
グローバル変数はデータセグメント(静的記憶領域)じゃないでしょうか。
>> ヒープ領域は、ポインタアドレスから実体を見にいくので、若干速度が遅い。
>↑らしいので、Aが遅くなるようにも思われますが、
今回はポインタを使ってないのでこれは関係無いかと思います。
というよりも
int main(){
int a, *b = malloc(sizeof(int));
a = 5;
00411CCB mov dword ptr [a],5
*b = 5;
00411CD2 mov eax,dword ptr
00411CD5 mov dword ptr [eax],5
}
ですので、mov 命令1個分の差です。 若干遅いと体感出来る速度差は生まれるはずは無いと思うんですが。
ちょっと眉唾なブログですね。
Re:while中のint
Posted: 2010年7月15日(木) 17:45
by ISLe
モトローラ系のMPUだとスタックをベースレジスタ+オフセットでアクセスするので、オフセットのバイト長が短い分有利です(でした?)ね。
PS3のCellとかPowerPCアーキテクチャのプロセッサはモトローラの設計思想を引き継いでいるし意外と影響あるかもしれません。
Re:while中のint
Posted: 2010年7月15日(木) 17:49
by めるぽん
効率を考えておくのは構いませんが、実際にコードを弄るのは、それが本当に問題になってからでいいでしょう。
「時期尚早な最適化は諸悪の根源だ」と偉い人も仰ってます。
ということで効率の面をおいておくなら、一般的に変数のスコープというのは出来る限り小さく保つのが好ましいと言われているので、最初の例が一番いいでしょう。
そうするのが、一番「開発効率」がいいです。
というより、最初の例と他の例で動作が変わってきませんか?
ループするたびに 0 に初期化されるのと最初だけ 0 に初期化するというのでは全く違う意味になると思うのですけど。
Re:while中のint
Posted: 2010年7月15日(木) 19:12
by ookami
# へろりさん
すみません、勘違いしておりました;;
ヒープは動的割り当ての領域なんですね...
混乱を招き、申し訳ありませんでした。
Re:while中のint
Posted: 2010年7月15日(木) 23:07
by ISLe
> ヒープは動的割り当ての領域なんですね...
間違ってないですよ。
基本的にデータセグメントには初期値だけが置かれて、グローバル変数はヒープを消費します。
初期値のないグローバル変数を宣言しても実行ファイルのサイズが同じだけ増えたりしないです。
Re:while中のint
Posted: 2010年7月16日(金) 09:53
by へろりくしょん
>基本的にデータセグメントには初期値だけが置かれて、グローバル変数はヒープを消費します
そうだったのですか。 また一つ勉強になりました。
ookamiさん私の言ったことは忘れてください。
しかし
#include <stdio.h>
int count = 10;
int main(void)
{
printf("%#x", &count);
return 0;
}
というコードを実行した結果は
0x40a128
となりました。
このプログラムのPEヘッダを調べてみると、
IMAGE_OPTIONAL_HEADER32.ImageBase = 0x00400000
IMAGE_OPTIONAL_HEADER32.BaseOfData = 0x0000a000
となっており、データセクションがメモリ上で 0x0040a000 に配置されることが解ります。
またデータセクションのヘッダを見ると、
IMAGE_SECTION_HEADER.VirtualAddress = 0x0000a000
IMAGE_SECTION_HEADER.Misk.VirtualSize = 0x00003000
となっており、メモリ上で 0x0040a000 から 0x0040d000 までがデータセクションとなるのでは無いでしょうか。
上記のコードを走らせた結果の 0x40a128 はこのデータセクションの範囲に入っていますので、
やっぱり変数 count の実体もデータセクションに配置されていると思うのですが。 どうなんでしょう。
ちょっと手元にWindowsしかなく、PEフォーマットでしか検証は出来ませんので、セクションという言葉を使ってますが許してください。
Re:while中のint
Posted: 2010年7月16日(金) 11:57
by たかぎ
> 基本的にデータセグメントには初期値だけが置かれて、グローバル変数はヒープを消費します。
そんなことはないでしょう。
Re:while中のint
Posted: 2010年7月16日(金) 12:29
by ookami
お騒がせしております;
# こういう時は、大元の言語仕様・コンパイラ仕様などを見たほうがよいのでしょうが、
# 見れてません。すみません。
サイトによって、説明のされ方が違うことまでは分かって参りました。
http://www1.cts.ne.jp/~clab/hsample/Point/Point19.html
>配置のされ方は、コンパイラやコンピュータによって一部違うものがあります
>データセグメントは ... 静的変数や大域変数(グローバル変数)が配置されます。
>ヒープ領域は ... malloc( )でメモリの割付が行われ、free( )の呼び出しで解放されます。
>スタックは ... 局所変数(ローカル変数)や、関数の引数が配置されます。
http://homepage2.nifty.com/well/Variable.html
>iValue1、acName、iValue2 はヒープに。 ... 結論的には、グローバル変数はヒープに取られるということです。
>システムによっては、ヒープに入らずに、特別なデータセグメントとして存在するかもしれませんが、ヒープに入ると考えてもプログラミング上は問題ありません。
Re:while中のint
Posted: 2010年7月16日(金) 18:53
by Poco
>
http://homepage2.nifty.com/well/Variable.html
> >iValue1、acName、iValue2 はヒープに。 ... 結論的には、グローバル変数はヒープに取られるということです。
> >システムによっては、ヒープに入らずに、特別なデータセグメントとして存在するかもしれませんが、ヒープに入ると考えてもプログラミング上は問題ありません。
こっちはかなり眉唾な気がします。
#全体的に論理展開がおかしい。。。
#プログラム組む上では問題ないかもしれないけど、人と話す上でこの前提はマズイだろ、と思います。
私もたかぎさんと同様、「そんなことない」と思ってまして、
ISLeさんの「基本的に」っていった処理系が知りたいです。
#確かWindowsの場合って、各セクションを仮想メモリに配置し、
#その後ヒープ(管理)の初期化を行っていたと記憶しています。
#なので、ヒープにグローバル変数が配置されるってのはちょっと納得できないですね。
#Inside Windowsにこの辺の解説があると思うんですが、誰か手元に持っていませんかね?
#UNIXライクなOSでもbss領域にグローバル変数(データセグメント上の情報)が展開されるって話、
#聞いたことないんですよね。。
Re:while中のint
Posted: 2010年7月16日(金) 19:41
by たかぎ
> #UNIXライクなOSでもbss領域にグローバル変数(データセグメント上の情報)が展開されるって話、
> #聞いたことないんですよね。。
組込み用の処理系などでは、初期値付きの静的変数は、スタートアップでROMやフラッシュメモリからRAMに転送されることは普通にあります。
しかし、転送先はあくまでもdataセクションであってヒープではありません。
Re:while中のint
Posted: 2010年7月16日(金) 23:43
by ISLe
ごめんなさい。
ヒープを消費するというのは間違いですね。
dataセクションやbssセクション用に(再)配置されるRAM領域をヒープに含まれると勘違いしました。
ヒープは別モノでしたね。