【C言語】
未定義動作より地味だが怖い
未規定動作と処理系定義動作

コンパイラで変わる 処理系定義の動作 int bit:1;

warning: comparison is always false due to limited range of data type

警告:データ型の範囲制限ため比較は常に偽になります。
[-Wtype-limits]


処理系定義の動作

#include    <stdio.h>
struct  tag {
    int bit:1;//処理系定義の動作
};
int main(void){
    struct tag  x;
    x.bit = 1;
    if(x.bit == 1){
        printf("gccはここに来ない");
    }else{
        printf("gccはここに来る bit = %d\n",x.bit);
    }
}

ビットフィールドを「単なる」int 型で定義してはいけない
signed/unsigned が明示されていない単なる int 型のビットフィールドのsigned/unsignedはコンパイラに依存します。
これを処理系定義の動作といいます。

gcc/clangの場合はsigned になるため
1bitしかないビットフィールドは
【0/-1】しか表現できません

1は表現できないので
     if(x.bit == 1){ 
は成立しません。


●ビットフィールドは unsigned int 型で定義する(推奨修正例)

#include    <stdio.h>
struct  tag {
    unsigned int bit:1;
};
int main(void){
    struct tag  x;
    x.bit = 1;
    if(x.bit == 1){
        printf("gccはここに来る bit = %d\n",x.bit);
    }else{
        printf("gccはここに来ない");
    }
}

signed/unsigned が明示されたビットフィールドは
コンパイラに依存しません

ビットフィールドは【0/1】を表現できるので
     if(x.bit == 1){ 
は成立します。

■未規定の動作

#include <stdio.h>
int a(void){    puts("A");  return  1;  }
int b(void){    puts("B");  return  2;  }
int c(void){    puts("C");  return  3;  }
int     main(void){
    printf("%d:%d:%d\n",a(),b(),c());
}

関数引数の評価順序は未規定の動作
このコードは
未規定の動作と言って
未定義の動作と違いバグではないのですが、
コンパイラによって動作が異なるので
避けて下さい。


gccの結果

./a.out
C
B
A
1:2:3

clangの結果

./a.out
A
B
C
1:2:3

参考:

EXP30-C. 副作用が発生する式の評価順序に依存しない

https://www.jpcert.or.jp/sc-rules/c-exp30-c.html

INT12-C. 式中で使用される単なるintのビットフィールドの型について勝手な想定をしない

https://www.jpcert.or.jp/sc-rules/c-int12-c.html