Last Update 2023/05/06
テスト概要
式の型と総称選択
副作用完了点
その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
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39
コード例・出力内容中の表記
・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。