2025
01
18
2012
05
27
値渡しとポインタ渡しで実行速度比較(C言語)
「C言語には値渡ししかないんだよ」みたいな突っ込みは置いておいて、 会社でCの関数書いてるときにどうでもいいローカル変数(関数先で値を変えない)を 値渡しにするか、constつけてポインタ渡しにして渡すかで速度変わるのかなーとか ぼんやり考えていたから実際に試してみた。 (実験プログラムでは、関数の引数でポインタとしている仮引数にconstを付けていないが、 関数先で値を変わってくることを期待していない変数であればconstをつけたほうがよいと思います。)
実験1 関数内で渡した変数に何もしない
/* pointer-test_none.c */ #define TRIAL_COUNT 100000000 void numeric(int a); void pointer(int *a); int main(void) { int i, num = 1; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num); #else numeric(num); #endif } return 0; } void numeric(int i) { ; } void pointer(int *i) { ; }
実験1のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_none pointer-test_none.c # コンパイル time ./pointer-test_none # 実行 ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.292 total ./pointer-test_none 0.29s user 0.00s system 99% cpu 0.291 total ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.292 total ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.292 total ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.294 total gcc -w -Wall -o pointer-test_none pointer-test_none.c # コンパイル time ./pointer-test_none # 実行 ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.318 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.317 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.318 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.318 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.317 total # 結果 値渡しのほうが、関数内で使う仮引数に値を一度コピーしているんだっけか、 速度がポインタ渡しのほうが速い結果となった。
実験2 関数内で渡した変数に10回アクセスする
/* pointer-test_sum.c */ #define TRIAL_COUNT 100000000 #define ACCESS_COUNT 10 void numeric(int a); void pointer(int *a); int main(void) { int i, num = 1; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num); #else numeric(num); #endif } return 0; } void numeric(int a) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += a; } } void pointer(int *a) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += *a; } }
実験2のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_sum pointer-test_sum.c # コンパイル time ./pointer-test_sum # 実行 ./point-test_sum 2.56s user 0.00s system 100% cpu 2.557 total ./point-test_sum 2.57s user 0.00s system 100% cpu 2.570 total ./point-test_sum 2.56s user 0.00s system 100% cpu 2.558 total ./point-test_sum 2.56s user 0.00s system 100% cpu 2.557 total ./point-test_sum 2.56s user 0.00s system 100% cpu 2.557 total gcc -w -Wall -o pointer-test_sum pointer-test_sum.c # コンパイル time ./pointer-test_sum # 実行 ./point-test_sum 2.44s user 0.00s system 100% cpu 2.438 total ./point-test_sum 2.44s user 0.00s system 100% cpu 2.432 total ./point-test_sum 2.44s user 0.00s system 100% cpu 2.432 total ./point-test_sum 2.42s user 0.01s system 99% cpu 2.431 total ./point-test_sum 2.44s user 0.00s system 100% cpu 2.434 total # 結果 ポインタ渡しをして、ポインタ介して変数の値をいちいち参照しているのか、 何度もアクセスすると、速度が値渡しのほうが速い結果となった。
実験3 関数内で渡した複数の変数に10回アクセスする
/* pointer-test_sum_many.c */ #define TRIAL_COUNT 100000000 #define ACCESS_COUNT 10 void numeric(int a, int b, int c); void pointer(int *a, int *b, int *c); int main(void) { int i, num1 = 1, num2 = 2, num3 = 3; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num1, &num2, &num3); #else numeric(num1, num2, num3); #endif } return 0; } void numeric(int a, int b, int c) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += (a + b + c); } } void pointer(int *a, int *b, int *c) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += (*a + *b + *c); } }
実験3のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_sum_many pointer-test_sum_many.c # コンパイル time ./pointer-test_sum_many # 実行 ./point-test_sum_many 3.21s user 0.00s system 100% cpu 3.208 total ./point-test_sum_many 3.21s user 0.00s system 100% cpu 3.206 total ./point-test_sum_many 3.21s user 0.00s system 100% cpu 3.208 total ./point-test_sum_many 3.21s user 0.00s system 99% cpu 3.211 total ./point-test_sum_many 3.20s user 0.02s system 100% cpu 3.214 total ./point-test_sum_many 3.15s user 0.08s system 100% cpu 3.226 total gcc -w -Wall -o pointer-test_sum_many pointer-test_sum_many.c # コンパイル time ./pointer-test_sum_many # 実行 ./point-test_sum_many 2.68s user 0.02s system 100% cpu 2.696 total ./point-test_sum_many 2.70s user 0.00s system 100% cpu 2.699 total ./point-test_sum_many 2.70s user 0.00s system 100% cpu 2.693 total ./point-test_sum_many 2.69s user 0.01s system 100% cpu 2.698 total ./point-test_sum_many 2.70s user 0.00s system 100% cpu 2.696 total # 結果 コピーする仮引数の数が増えればとポインタ渡しのほうが速くなるかなと思ったが、 ポインタ介して変数の値を参照する回数のほうが今回の実験では影響大なためか 値渡しのほうが速い結果となった。
実験4 関数内で渡した複数の変数に10回アクセスする (ローカル変数に一度コピー)
本末転倒だが、ポインタで渡した変数の中身を、ローカル変数に一度コピーして 実験してみた。
/* pointer-test_sum_many2.c */ #define TRIAL_COUNT 100000000 #define ACCESS_COUNT 10 void numeric(int a, int b, int c); void pointer(int *a, int *b, int *c); int main(void) { int i, num1 = 1, num2 = 2, num3 = 3; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num1, &num2, &num3); #else numeric(num1, num2, num3); #endif } return 0; } void numeric(int a, int b, int c) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += (a + b + c); } } void pointer(int *a, int *b, int *c) { int i, sum = 0; int aa = *a, bb = *b, cc = *c; /* <- koko!! */ for (i = 0; i < ACCESS_COUNT; i++) { sum += (aa + bb + cc); } }
実験4のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_sum_many2 pointer-test_sum_many2.c # コンパイル time ./pointer-test_sum_many2 # 実行 ./point-test_sum_many2 2.97s user 0.00s system 100% cpu 2.967 total ./point-test_sum_many2 2.97s user 0.00s system 100% cpu 2.963 total ./point-test_sum_many2 2.97s user 0.00s system 100% cpu 2.964 total gcc -w -Wall -o pointer-test_sum_many2 pointer-test_sum_many2.c # コンパイル time ./pointer-test_sum_many2 # 実行 ./point-test_sum_many2 2.69s user 0.00s system 100% cpu 2.689 total ./point-test_sum_many2 2.70s user 0.00s system 100% cpu 2.692 total ./point-test_sum_many2 2.69s user 0.00s system 100% cpu 2.688 total # 結果 ポインタ介してアクセスする回数が減ったけども、ローカル変数に一度コピーする ことが影響しているのか、ただ値渡しにするよりもポインタ渡しのほうが遅い結果となった。
実験のまとめ
・関数内で引数で渡してきた変数の中身に何度もアクセスしないのであれば、 ポインタ渡しのほうが速い(仮引数を作りコピーする処理がないため) ※冒頭でも書きましたが、上記の場合はconstをつけたほうが見る人は、 「この変数は関数の先で変わってくることを期待していないんだな」とわかるので、 つけたほうがいいと思います。 ・逆に何度もアクセスするのであれば、値渡しにしてしまったほうが速い (ポインタ介して値を引っ張ってくるため(であってる?))
検索用タグ C言語 実行速度
PR
2012/05/27 (Sun.) Comment(0) C言語
2012
05
27
「プログラマにお使いを頼んだら……」(C言語)
「プログラマにお使いを頼んだら……」のジョーク内のプログラマーの思考をC言語で書いてみた。
ジョーク概要
“Could you please go shopping for me and buy one carton of milk, and if they have eggs, get 6!” ある妻がプログラマの夫に「買い物にいって牛乳を1つ買ってきてちょうだい。卵があったら6つお願い」と言った。 A short time later the husband comes back with 6 cartons of milk. 夫はしばらくして、牛乳を6パック買ってきた。 The wife asks him, “Why the hell did you buy 6 cartons of milk?” 妻は聞いた「なんで牛乳を6パックも買ってきたのよ!」 He replied, “They had eggs.” 夫いわく「だって、卵があったから……」
gyunyu.c
/* gyunyu.c */ #include <stdio.h> #define EXIST 1 #define NOEXIST 0 int main(void) { int buy_milk = 1; if (is_eggs_exist()) { buy_milk = 6; } printf("Buy %d carton of milk.\n", buy_milk); return 0; } int is_eggs_exist() { return EXIST; }
コンパイルと実行結果
gcc -w -Wall gyunyu gyunyu.c ./gyunyu Buy 6 carton of milk.
検索用タグ C言語
2012/05/27 (Sun.) Comment(0) C言語
2012
05
13
LinuxでPython実行環境を整える
お遊び半分ででPythonしたくなったので、インストールから実行まで学習したことをまとめる。 環境:Scientific Linux 6.2 64bit
インストールされているか確認
python -V # Python のバージョンが表示されればインストール済み # (ちなみにPython 2.6.6が入っていました。)
インストールの仕方
# ダウンロード&インストール wget http://www.python.org/ftp/python/3.2/Python-3.2.tgz tar zxvf Python-3.2.tgz cd Python-3.2 ./configure make make install # パスの設定 ls -l /usr/bin | grep python # 元々インストールされている場所 ls -l /usr/local/bin | grep python # 新しくインストールされた場所 sudo mv /usr/bin/python /usr/bin/python2.6.old # 「python」で起動されないよう改名 sudo mv /usr/local/bin/python3 /usr/local/bin/python # 「python」で起動されるよう改名 # 環境設定ファイルの編集 vi .zshrc # .bashrcなどの設定ファイルを開く ##-----(設定ファイル内)----------------- export PATH="$PATH":/usr/local/bin # 追記
実行(Hello world表示)
## ---------対話型で実行----------- python # 起動 print ("Hello, world!") # Enterで実行 ## -------ファイルから実行--------- cat >> hello.py # ファイル編集始め print ("Hello, world!") # Ctrl+d を入力し、ファイル編集終わらせる chmod u+x hello.py # 実行権の変更 python hello.py # 実行
その他
・print Hello, world!としたら「python syntaxError invalid syntax」と 出てエラーをはかれた。どうやらPython3からいくつか文法が変更され、 printは、構文から関数になったらしく、カッコが必須みたいです。 ・python バージョン2のほうがよさげですね・・
検索用タグ Python
2012/05/13 (Sun.) Comment(0) Python
2012
04
24
設定ファイルから特定パラメータを文字列で取得(C言語)
設定ファイルから設定を読み込むのに使います。
ソースコード
/* get_param.c */ #include <stdio.h> #include <string.h> #define STR_MAX 256 #define CONFIG_FILE "config.txt" void usage(void) { printf("usage: ./get_param [parameter_name]\n"); } int main(int argc, char *argv[]) { int i = 0, j = 0; char str[STR_MAX], param[STR_MAX]; FILE *fin; if (argc < 2) { usage(); return -2; /* operation miss */ } if ((fin = fopen(CONFIG_FILE, "r")) == NULL) { printf("fin error:[%s]\n", CONFIG_FILE); return -1; /* system error */ } for(;;) { if (fgets(str, STR_MAX, fin) == NULL) { /* EOF */ fclose(fin); return -3; /* not found keyword */ } if (!strncmp(str, argv[1], strlen(argv[1]))) { while (str[i++] != '=') { ; } while (str[i] != '\n') { param[j++] = str[i++]; } param[j] = '\0'; printf("param:[%s]\n", param); fclose(fin); return 0; } } fclose(fin); return -1; /* not reachable */ }
コンパイル例
gcc -Wall -o get_param get_param.c
使い方
./get_param [parametor_name]
使用例
# config.txt 中身 IP=192.168.1.14 PORT=11104 SDI_IN=enable ・ ・ ・
実行
nex2t@nex2t-svr$ ./get_param IP /home/nex2t param:[192.168.1.14] nex2t@nex2t-svr$ ./get_param PORT /home/nex2t param:[11104] nex2t@nex2t-svr$ ./get_param SDI_IN /home/nex2t param:[enable]
検索用タグ C言語
2012/04/24 (Tue.) Comment(0) C言語
2012
04
23
ネット対戦できる将棋ゲーム(C言語&GTK+)
余暇の時間で作った将棋ゲー 基本的な部分はできたので、もっと遊び的な機能を付けていきたい。
検索用タグ C言語
2012/04/23 (Mon.) Comment(0) GTK+