【C言語】
ビット反転【~】と
論理反転【!】の違い

■【チルダ~】対【ビックリマーク!】

●ビット反転【チルダ
1 ⇒~ビット反転 ⇒0xFFFFfffE(2進数1111…0)
0 ⇒~ビット反転 ⇒0xFFFFfffF(2進数1111…1)

●論理反転【ビックリマーク
1 (真)⇒!論理反転 ⇒0(偽)
0 (偽)⇒!論理反転 ⇒1(真)


■&&でなくて&でしょう

warning: ‘~’ on a boolean expression

警告:ブール式で’~’チルダが使われた
[-Wbool-operation]

#include    <stdio.h>
#include    <stdbool.h>
#include    <stdint.h>
void f1(uint32_t x,uint32_t y)
{
    uint32_t z;
    z = ~(x && y);  //NG
    printf("%x\n",z);
    z = ~(x & y);  //OK
    printf("%x\n",z);
}

~ビット反転と!論理否定とは違います。
論理式に対して~演算子を使用してビット反転するのは
誤りの可能性があります。
多分
&&ではなくて
 でしょう


■~でなくて!でしょう

void f2(bool x,bool y)
{
    bool z;
    z = ~(x && y); //NG
    printf("%x\n",z);
    z = !(x && y); //OK
    printf("%x\n",z);
}


論理式に対して~演算子を使用してビット反転するのは
誤りの可能性があります。
多分ではなくてでしょう


■bool型変数に~演算子?

void f3(bool x)
{
    //怪しい:bool型のビット反転
    printf("%x\n",~x); //NG
        //以下のどちらかにしかならない
        //->ffffffff
        //->fffffffe

    printf("%x\n",!x);
}

bool型変数に対して~演算子を使用してビット反転すると
0xffffffff  か
0xfffffffe にしかならないので
誤りの可能性があります。
多分ではなくてでしょう


■16進数定数に!演算子?

void f4(void)
{
    uint32_t    x = !0x2;//NG:16進数を論理反転
    printf("%x\n",x);  
    uint32_t    y = ~0x2 ;//OK 
    printf("%x\n",y);  
}

16進数定数を!演算子を使用して論理反転するのは
誤りの可能性があります。
多分ではなくてでしょう。
#残念ながらgcc/clangで警告は現状でません。

■is系関数に~チルダを使用

#include <stdio.h>
#include <ctype.h>
//X<ctype.h>のis系関数に~チルダを使用
void 間違い(char *string){
    for(char *p = string ; *p;p++){
        if(~isalpha(*p)){
            printf("%s:アルファベットじゃない %c\n",__func__,*p);       
        }
    }
}
//◎<ctype.h>のis系関数に!ビックリを使用
void 正解(char *string){
    for(char *p = string; *p;p++){
        if(!isalpha(*p)){
            printf("%s:アルファベットじゃない %c\n",__func__,*p);        
        }
    }
}
int main(void){
    static char *string = "abc123def456?#$%&";
    間違い(string);
    puts("--------");
    正解(string);
}

<ctype.h>で提供されているis系関数に対して
ビット演算子の~を使用するのは恐らく間違いでしょう。

■練習問題:何と表示されますか?

#include <stdio.h>
#include <stdbool.h>
//ド・モルガンの法則実装誤り
static  void 誤り(bool x,bool y){
    if((~x && ~y) == ~(x || y)) puts("同じ");
    else                        puts("違う");
    if((~x || ~y) == ~(x && y)) puts("同じ");
    else                        puts("違う");
}   
//ド・モルガンの法則実装正解
static  void 正解(bool x,bool y){
    if((!x && !y) == !(x || y)) puts("同じ");
    else                        puts("違う");
    if((!x || !y) == !(x && y)) puts("同じ");
    else                        puts("違う");
}   
int main(void){
    誤り(0,0);
    誤り(0,1);
    誤り(1,0);
    誤り(1,1);

    正解(0,0);
    正解(0,1);
    正解(1,0);
    正解(1,1);
}