web-dev-qa-db-ja.com

TRUEおよびFALSEマクロの奇妙な定義

私はコーディングブックで次のマクロ定義を見てきました。

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

そこには説明がありませんでした。

これらがTRUEおよびFALSEとしてどのように機能するかを説明してください。

294
Keshava GN

見てみましょう:'/' / '/'は、charリテラル/を、charリテラル'/'自体で割ったものを意味します。結果は1つで、TRUEにとって妥当なように思えます。

_'-' - '-'は、charリテラル'-'を意味し、それ自体から減算されます。これはゼロ(FALSE)です。

これには2つの問題があります。1つ目は、読み取り不能です。 10を使用するのは絶対に良い方法です。また、TartanLlamaとKerrekSBが指摘したように、その定義を使用する予定がある場合は、驚かないように括弧を追加してください。

#include <stdio.h>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() {
        printf ("%d\n", 2 * FALSE);
        return 0;
}

これは、charリテラル'-'(私のシステムでは45)の値を出力します。

括弧付き:

#define TRUE  ('/'/'/')
#define FALSE ('-'-'-')

真理値に整数を掛けるのはあまり意味がありませんが、プログラムは正しくゼロを出力しますが、マクロを括弧に入れない場合に噛みつく可能性のある予期しないバグの例にすぎません。

374
Jay

それはただの別の書き方です

#define TRUE 1
#define FALSE 0

'/'/'/'は、'/'のchar値をそれ自体で除算し、結果として1を返します。

'-'-'-'は、'-'のchar値をそれ自体から減算し、結果として0を返します。

ただし、define式全体を囲む括弧が欠落しているため、これらのマクロを使用するコードでエラーが発生する可能性があります。 ジェイの答え それはかなりうまくいきます。

ブラケットを忘れると有害になる可能性がある「実際の」シナリオの例は、これらのマクロをCスタイルのキャスト演算子と組み合わせて使用​​することです。たとえば、C++でこれらの式をboolにキャストすることにした場合:

#include <iostream>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() {
    std::cout << "True: " << (bool) TRUE << std::endl;
    std::cout << "False: " << (bool) FALSE << std::endl;
    return 0;
}

取得するものは次のとおりです。

True: 0
False: -44

したがって、(bool) TRUEは実際にfalseに評価され、(bool) FALSEtrueに評価されます。

87
BlackDwarf

書くことと同等です

#define TRUE 1
#define FALSE 0

'/'/'/'が実際に行うことは、文字/(その数値が何であれ)をそれ自体で除算することであるため、1になります。

同様に、式'-'-'-'は、それ自体から文字-を減算し、0と評価します。

書く方が良いでしょう

#define TRUE ('/'/'/')
#define FALSE ('-'-'-')

他の優先順位の高い演算子と一緒に使用した場合に、値が誤って変更されるのを防ぎます。

44
0605002

Jay これらの式の値が01である理由はすでに答えています。

歴史のために、これらの式'/'/'/'および'-'-'-'は、 1984年の第1回国際難読化Cコードコンテスト :のエントリのいずれかに由来します。

int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}

(プログラムへのリンク ここ 、上記のIOCCCページにこのプログラムが行うことのヒントがあります。)

また、TRUEおよびFALSEの難読化されたマクロとしてのこれらの式が "難読化されたCおよびその他のミステリー" Don Libes(1993)でカバーされていることも覚えています。

32
ouah

真から始めましょう。これは'/' / '/'として読むことができます。これは「文字 '/'を文字 '/'で割ったもの」を意味します。 Cの各文字は数値(1バイト)であるため、「_ '<'> 'のASCIIの値をASCIIの値で割った値」として読み取ることができます。同じ文字」、つまり1を意味します(明らかに、x/xは1であるため)。したがって、TRUEは1です。

FALSEの場合、同じ理由:'-'-'-''-' - '-'を読み取ります。つまり、「-'のASCII値から'-'のASCII値を引いた' 0 'です。したがって、FALSE 0です。

これは明白なことを述べる厄介な方法です。

6
Fabien