Loose-Info.com
Last Update 2023/05/06
TOP - 各種テスト - C言語 - 式

テスト概要

その1
式の型と総称選択

その2
副作用完了点


その1

式の型と総称選択

sample1.c
#include <stdio.h> #include <stdlib.h> /* 総称選択 */ #define seltype(arg) _Generic(arg, \ char *: type_char, \ int: type_int, \ double: type_double) (arg) void type_char(char *arg) { printf("%s ---> char *\n", arg); } void type_int(int arg) { printf("%d ---> int\n", arg); } void type_double(double arg) { printf("%e ---> double\n", arg); } int main(void) { double d; printf("(1) "); seltype("abc"); printf("(2) "); seltype(123 + 456); printf("(3) "); seltype(printf("printf ---> ")); printf("(4) "); seltype(1.23 * 456); printf("(5) "); seltype(1.23 == 456); printf("(6) "); seltype(d = 1.23); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c $ ./a.out (1) abc ---> char * (2) 579 ---> int (3) printf ---> 12 ---> int (4) 5.608800e+02 ---> double (5) 0 ---> int (6) 1.230000e+00 ---> double

その2

副作用完了点

sample2.c
#include <stdio.h> #include <stdlib.h> static int sti; int sampfunc(char *s, int i1, int i2) { i1++; printf("%s %d %d\n", s, i1, i2); /* return内の式の評価後が副作用完了点 */ return (++i1) + (sti++); } int main(void) { sti = 1; int i1 = 0; /* i1を1回だけ変更 */ i1 = i1 + 1; /* i1を1回だけ変更 */ i1 = i1++; /* i1を2回変更【操作結果未定義の可能性有り】 */ int i2 = 1; /* i2を1回だけ変更 */ int i3 = 0; /* i3を1回だけ変更 */ /* i3は2回変更 */ i3 = (i1++) + (++i2) + (i3++); /* 【操作結果未定義の可能性有り】 */ /* for文の三つの制御式はそれぞれ副作用完了点で分離 */ /* i2の変更は各制御式内毎に1回 */ for (i2--; ++i2 < 10; i2++) { i2++; printf("i1 = %d : i2 = %d\n", i1, i2); } /* while文の制御式評価後の反復処理前が副作用完了点 */ /* 反復処理コードへの影響は無し */ while (--i2 > 2) { i2--; printf("i2(while) = %d\n", i2); } /* while文の制御式評価後の反復処理前が副作用完了点 */ /* 反復処理コードへの影響は無し */ do { i2++; printf("i2(do) = %d\n", i2); } while (i2++ < 10); /* 関数の全引数評価中にi1を2回変更 */ i2 = sampfunc("abc", ++i1, i1++); /* 【操作結果未定義の可能性有り】 */ /* 関数内のreturn文実行後に副作用完了点 */ /* 戻り値によるsiの変更には影響無し */ printf("sti = %d\n", sti = sampfunc("def", ++i1, i2++)); /* 条件式終了後が副作用完了点 */ /* 選択後のコードへの影響は無し */ if (i1 < i2++) { i2++; printf("i2(1) = %d\n", i2); } /* 論理演算子&&の第1オペランド評価後が副作用完了点 */ /* 続く式への影響は無し */ if ((i1 < i2++) && (i3 < i2++)) { i2++; printf("i2(2) = %d\n", i2); } /* 論理演算子||の第1オペランド評価後が副作用完了点 */ /* 続く式への影響は無し */ if ((i1 > i2++) || (i3 < i2++)) { i2++; printf("i2(3) = %d\n", i2); } /* 条件演算子の第1オペランド評価後が副作用完了点 */ /* 選択後のコードへの影響は無し */ i3 < ++i2 ? i2++ : i2--; printf("i2(4) = %d\n", ++i2); /* コンマ演算子の第1オペランド評価後が副作用完了点 */ /* 続く式への影響は無し */ i1 = i3++ , i2 = ++i3; printf("i2(5) = %d\n", ++i2); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample2.c sample2.c: In function ‘main’: <--- 以下、副作用完了点間に2度以上のオブジェクトの変更を伴う場合の警告発生 sample2.c:21:12: warning: operation on ‘i1’ may be undefined [-Wsequence-point] 21 | i1 = i1++; /* i1を2回変更【操作結果未定義の可能性有り】 */ | ~~~^~~~~~ sample2.c:26:12: warning: operation on ‘i3’ may be undefined [-Wsequence-point] 26 | i3 = (i1++) + (++i2) + (i3++); /* 【操作結果未定義の可能性有り】 */ | ~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ sample2.c:41:38: warning: operation on ‘i1’ may be undefined [-Wsequence-point] 41 | i2 = sampfunc("abc", ++i1, i1++); /* 【操作結果未定義の可能性有り】 */ | ~~^~ $ ./a.out i1 = 2 : i2 = 3 i1 = 2 : i2 = 6 i1 = 2 : i2 = 9 i2(while) = 9 i2(while) = 7 i2(while) = 5 i2(while) = 3 i2(do) = 3 i2(do) = 5 i2(do) = 7 i2(do) = 9 i2(do) = 11 abc 5 2 def 6 7 sti = 9 i2(1) = 10 i2(2) = 13 i2(3) = 16 i2(4) = 19 i2(5) = 6

実行環境

GNU bash, version 5.1.16
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39


コード例・出力内容中の表記

・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。