Neden #define C yerine bir Boole makroda 1 yerine TRUE (1 == 1)


160

C'de tanımları gördüm

#define TRUE (1==1)
#define FALSE (!TRUE)

Bu gerekli mi? TRUE değerini 1 ve FALSE değerini 0 olarak tanımlamanın avantajı nedir?


35
Ve daha fazlası #define TRUE (’/’/’/’):; #define FALSE (’-’-’-’)( coding-guidelines.com/cbook/cbook1_1.pdf sayfa 871 adresinden alınmıştır )
osgx

2
Hayır, gerçekten clueless ^ Wunderinformed tarafından paranoya. C, 1 ve 0'da her koşulda aynı şeyi yaparlar.
Jens

@osgx Ne anlama geliyor?
mrgloom

Yanıtlar:


155

Bu yaklaşım , derleyici destekliyorsa gerçek booleantürü kullanır (ve çözümlemesi trueve için false). (özellikle C ++)

Ancak, C ++ (aracılığıyla kullanımda olup olmadığını kontrol etmek daha iyi olurdu __cplusplusmakro) ve aslında kullanmak trueve false.

Bir Cı derleyici, bu eşdeğerdir 0ve 1.
(parantezlerin kaldırılmasının işlem sırası nedeniyle kesileceğini unutmayın)


7
Bu yanlış, burada bools kullanılmıyor. Sonucu 1==1bir int. (bkz. stackoverflow.com/questions/7687403/… .)
Mat

4
@Mat: C ++ ile bile, booleantürü ile?
SLaks

9
Soru C olarak etiketlenir, ancak gerçekten C ++ 'da ilişkisel işleçler döndürür trueveya false.
Mat

5
@Mat: C ++ ile iyi oynamak için bu tür kodların C başlıklarına yazıldığını tahmin ediyorum
SLaks

20
@SLaks Eğer C ++ ile güzel oynamak isterse , ne zaman #define TRUE trueve #define FALSE falsene zaman __cplusplustanımlanır.
Nikos

137

Cevap taşınabilirliktir. Sayısal değerleri önemlidir TRUEve FALSEönemli değildir. Ne olduğunu önemlidir gibi bir deyimi o if (1 < 2)kadar değerlendirir if (TRUE)ve benzeri bir açıklamada if (1 > 2)için değerlendirir if (FALSE).

C olarak kabul (1 < 2)edilir 1ve (1 > 2)değerlendirilir 0, diğerlerinin söylediği gibi, derleyici açısından pratik bir fark yoktur. Ancak derleyicinin kendi kurallarına göre tanımlamasına TRUEve FALSEkendi kurallarına göre, anlamlarını programcılara açık hale getiriyorsunuz ve programınızdaki ve diğer kütüphanelerinizde tutarlılığı garanti ediyorsunuz (diğer kütüphanenin C standartlarına uyduğu varsayılırsa ... şaşıracaksınız).


Bazı Geçmişi
Bazı BASICler tanımlandığı FALSEşekilde 0ve TRUEolduğu gibi -1. Birçok modern dil gibi , sıfır olmayan herhangi bir değeri olarak yorumladılarTRUE , ancak doğru olan boole ifadelerini değerlendirdiler-1 . Onların NOTo bu şekilde yapmaya verimli olduğu için operasyon, 1 ekleme ve işareti saygısız tarafından hayata geçirildi. Böylece 'NOT x' oldu -(x+1). Bunun bir yan etkisi, benzeri bir değerin 5değerlendirildiği TRUE, ancak NOT 5değerlendirildiği -6, ki bu da TRUE! Bu tür bir hata bulmak eğlenceli değil.

İyi Uygulamalar
Verilen fiilen sıfır olarak yorumlanır olduğunu kurallarını FALSEve herhangi olarak sıfır olmayan bir değer yorumlanır TRUEsen gerektiğini boole görünümlü ifadeleri karşılaştırmak asla TRUEyaFALSE . Örnekler:

if (thisValue == FALSE)  // Don't do this!
if (thatValue == TRUE)   // Or this!
if (otherValue != TRUE)  // Whatever you do, don't do this!

Neden? Çünkü birçok programcı ints'yi tedavi etme kısayolunu kullanır bool. Aynı değiller, ancak derleyiciler genellikle buna izin verir. Yani, örneğin, yazmak tamamen yasal

if (strcmp(yourString, myString) == TRUE)  // Wrong!!!

Bu meşru görünüyor ve derleyici bunu mutlu bir şekilde kabul edecek, ancak muhtemelen istediğinizi yapmaz. Yani en yüzünden dönüş değeri strcmp()DİR

      0 ise yourString == myString
    <0 ise yourString < myString
    > 0 iseyourString > myString

Yani yukarıdaki çizgi TRUEsadece ne zaman geri döner yourString > myString.

Bunu yapmanın doğru yolu ya

// Valid, but still treats int as bool.
if (strcmp(yourString, myString))

veya

// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)

Benzer şekilde:

if (someBoolValue == FALSE)     // Redundant.
if (!someBoolValue)             // Better.
return (x > 0) ? TRUE : FALSE;  // You're fired.
return (x > 0);                 // Simpler, clearer, correct.
if (ptr == NULL)                // Perfect: compares pointers.
if (!ptr)                       // Sleazy, but short and valid.
if (ptr == FALSE)               // Whatisthisidonteven.

Genellikle bu "kötü örneklerin" bazılarını üretim kodunda bulacaksınız ve birçok deneyimli programcı onlar tarafından yemin ediyor: çalışıyorlar, bazıları (bilgiçlik?) Doğru alternatiflerinden daha kısadır ve deyimler neredeyse evrensel olarak tanınır. Ancak şunu düşünün: "doğru" sürümler daha az verimli değildir, taşınabilir olmaları garanti edilir, en katı linterleri bile geçer ve hatta yeni programcılar bile bunları anlar.

Buna değmez mi?


6
(1==1)daha taşınabilir değil 1. Derleyicinin kendi kuralları, eşitlik ve ilişkisel işleçlerin anlambilimi konusunda açık ve net olan C dilinin kurallarıdır. Bir derleyicinin bu şeyleri yanlış yaptığını hiç görmedim.
Keith Thompson

1
Aslında, döndürülen değerin strcmp0'dan küçük, eşit veya 0'dan büyük olduğu bilinmektedir. -1, 0 veya 1 olduğu garanti edilmez ve wild'da uygulama hızını kazanmak için bu değerleri döndürmeyen platformlar vardır. Eğer strcmp(a, b) == TRUEöyleyse, a > bancak ters ima tutunmayabilir.
Maciej Piechotka

2
@KeithThompson - Belki de "taşınabilirlik" yanlış terimdi. Ancak gerçek şu ki (1 == 1) bir boole değeri; 1 değil.
Adam Liss

2
@AdamLiss: C cinsinden (1==1)ve 1her ikisi de int1 değerine sahip sabit tip ifadelerdir. Anlamsal olarak aynıdırlar. Sanırım bunu bilmeyen okuyuculara hitap eden bir kod yazabilirsiniz, ama nerede bitiyor?
Keith Thompson

2
'not' 5 aslında -6, bit seviyesinde.
woliveirajr

51

(1 == 1)Hüner tanımlamak için yararlıdır TRUEC ++ şeffaf bir şekilde, henüz C daha iyi yazarak sağlar. "Temiz C" (C veya C ++ olarak derlenen) bir lehçede yazıyorsanız veya C veya C ++ programcıları tarafından kullanılabilecek API başlık dosyaları yazıyorsanız, aynı kod C veya C ++ olarak yorumlanabilir.

Cı çeviri birimleri olarak, 1 == 1tam olarak aynı anlamlara sahiptir 1; ile 1 == 0aynı anlama sahiptir 0. Ancak, C ++ çeviri birimlerinde 1 == 1türü vardır bool. Yani TRUEbu şekilde tanımlanan makro C ++ 'a daha iyi entegre olur.

Nasıl daha iyi entegre edileceğinin bir örneği, örneğin işlev fooiçin intve için aşırı yük varsa bool, o foo(TRUE)zaman boolaşırı yükü seçecektir . Eğer TRUEsadece olarak tanımlanır 1, o zaman C ++ içinde güzel çalışmayacaktır. aşırı yük foo(TRUE)isteyecek int.

Tabii ki, C99 tanıtıldı bool, trueve falsebu başlık dosyalarında kullanılabilen C99 ile ve C ile çalışmak olduğunu

Ancak:

  • belirlenmekte olduğu bu uygulama TRUEile FALSEolduğu gibi (0==0)ve (1==0)C99 eskidir.
  • C99'dan uzak durmak ve C90 ile çalışmak için hala iyi nedenler var.

Eğer bir karma C ve C ++ projede çalışıyoruz ve C99 istemiyorsanız, alt durum tanımlamak true, falseve boolbunun yerine.

#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif

Bununla birlikte, 0==0hile, bazı programcılar tarafından hiçbir zaman C ++ ile birlikte çalışması amaçlanmayan kodda bile kullanıldı (?). Bu hiçbir şey satın almaz ve programcının C'de boolelerin nasıl çalıştığını yanlış anladığını gösterir.


C ++ açıklaması net değilse, bir test programı aşağıdadır:

#include <cstdio>

void foo(bool x)
{
   std::puts("bool");  
}

void foo(int x)
{
   std::puts("int");  
}

int main()
{
   foo(1 == 1);
   foo(1);
   return 0;
}

Çıktı:

bool
int

Aşırı C ve C ++ programlama ile ilgili aşırı yüklenmiş C ++ fonksiyonlarının yorumlarından gelen soruya gelince. Bunlar sadece bir tip farkı göstermektedir. C ++ olarak derlendiğinde bir truesabitin olmasını istemenin geçerli bir nedeni booltemiz teşhis içindir. En yüksek uyarı düzeylerinde, bir C ++ derleyicisi boolparametre olarak bir tamsayıyı iletirsek, dönüşüm konusunda bizi uyarabilir . Temiz C'de yazmanın bir nedeni sadece kodumuzun daha taşınabilir olması değildir (çünkü sadece C derleyicileri değil, C ++ derleyicileri tarafından da anlaşılır), ancak C ++ derleyicilerinin tanılama görüşlerinden de yararlanabiliriz.


3
Mükemmel ve takdir edilmemiş bir cevap. İki tanımının TRUEC ++ altında farklılık göstereceği açık değildir .
user4815162342

4
Aşırı yüklenmiş işlevler hem C hem de C ++ olarak derlenen kodla nasıl ilişkilidir?
Keith Thompson

@KeithThompson Bu sadece aşırı yükleme ile ilgili değil, genel olarak doğru yazma ile de ilgili, aşırı yükleme sadece oyuna geldiğinde en pratik örnektir. Tabii ki aşırı yükler, şablonlar ve "C-uyumluluğu" için kaldırılan "karmaşık" şeyler olmadan C ++ kodu, türler hakkında pek fazla umursamıyor, ancak bu, belirli bir dilde kavramsal tür sınırlamalarını aşması gerektiği anlamına gelmez. .
Christian Rau

1
@ChristianRau: Ne demek "tipler hakkında pek umursamıyor"? Türler C dilinin merkezindedir; C programındaki her ifade, değer ve nesne iyi tanımlanmış bir türe sahiptir. C ve C ++ 'da ( hem C hem de C ++ olarak derlenen kodu yazmanız gereken nadir durumlarda) farklı bir şey tanımlamak istiyorsanız #ifdef __cplusplus, niyetinizi çok daha açık bir şekilde ifade etmek için kullanabilirsiniz .
Keith Thompson

@KeithThompson Evet Türlerin ne kadar önemli olduğunu biliyorum. Bu sadece tüm olmadan aşırı ve şablonları, şeyler arasındaki farklılaşma gibi gibi tip-farkında şeyler boolve intörtük birbirlerine dönüştürülebilir (ve de çünkü çok önemli değil pratikte do C aslında "aynı" , tırnak dikkat olsa da) ve ikisi arasında gerçekten saptamanız gereken birçok durum yok . "fazla değil" muhtemelen çok ağırdı, "şablonlar ve aşırı yükleme kullanan kodlara kıyasla çok daha az" belki daha iyi olurdu.
Christian Rau

18
#define TRUE (1==1)
#define FALSE (!TRUE)

eşittir

#define TRUE  1
#define FALSE 0

C cinsinden

İlişkisel işleçlerin sonucu 0veya 1. 1==1için değerlendirilmesi 1ve değerlendirilmesi için !(1==1)garanti edilir 0.

İlk formu kullanmak için kesinlikle hiçbir neden yoktur. Bununla birlikte, birinci formun hemen hemen tüm derleyicilerde olduğu gibi, sabit bir ifadenin çalışma zamanında değil, derleme zamanında değerlendirildiğini unutmayın. Bu kurala göre izin verilir:

(C99, 6.6p2) "Sabit bir ifade, çalışma sırasında değil çeviri sırasında değerlendirilebilir ve buna göre, bir sabitin olabileceği herhangi bir yerde kullanılabilir."

PC-Lint, için hazır bilgi TRUEve FALSEmakro kullanmazsanız bir ileti (506, sabit değer boole) bile gönderir :

C için, TRUEolarak tanımlanmalıdır 1. Bununla birlikte, diğer diller 1 dışındaki miktarları kullanır, bu nedenle bazı programcılar !0bunu güvenli oynadığını düşünür.

Ayrıca C99'da, stdbool.hboolean makroları trueve false doğrudan değişmez değerleri tanımları :

#define true   1
#define false  0

1
Şüphem var, DOĞRU her kullanımda 1 == 1 ile değiştirilirken, sadece 1 kullanıldığında 1 yerine geçecek, ilk yöntem ekstra karşılaştırma yükü değil mi ...
pinkpanther

4
@pinkpanther sabit ifadeleri genellikle derleme zamanında değerlendirilir ve bu nedenle ek yük oluşturmaz.
ouah

2
1==11
ouah

3
@NikosC. bu iyi bir soru. Bu if(foo == true), sadece kötü uygulamadan düz arabayı alacak olan formun kodu için önemlidir .
djechlin

1
Tehlikeleri belirtmek için +1 (x == TRUE), bundan farklı bir gerçek değerine sahip olabilir x.
Joshua Taylor

12

C ++ (daha önce de belirtilmiş) dışında, bir diğer avantaj da statik analiz araçlarıdır. Derleyici herhangi bir verimsizliği ortadan kaldıracaktır, ancak statik bir analizör karşılaştırma sonuçlarını ve diğer tamsayı tiplerini ayırt etmek için kendi soyut tiplerini kullanabilir, bu nedenle dolaylı olarak TRUE'nun bir karşılaştırmanın sonucu olması gerektiğini ve uyumlu olduğu varsayılmaması gerektiğini bilir. bir tamsayı ile.

Açıkçası C uyumlularsa olduğunu söylüyor, ancak yardım vurgulamak hatalar için bu özellik kasıtlı kullanımını yasaklayan tercih edebilir - örneğin, birileri karıştırmayın olabilir nerede &ve &&ya onların operatör öncelik bungled ettik.


1
Bu iyi bir nokta ve belki de bu araçlardan bazıları , düğümün gelişmiş tip bilgisi sayesinde desene düştüğü if (boolean_var == TRUE) genişleme yoluyla aptalca kod yakalayabilir . if (boolean_var == (1 == 1))(1 == 1)if (<*> == <boolean_expr>)
Kaz

4

Pratik fark yok. 0olarak değerlendirilir falseve 1olarak değerlendirilir true. Bir kullanmak gerçeği boolean ifadesini ( 1 == 1) ya da 1tanımlamak için, trueherhangi bir fark yaratmaz. İkisi de değerlendirilir int.

Uyarı C standart kütüphanesi Boolean tanımlamak için özel bir başlık sağladığını: stdbool.h.


Tabii ki
yapmadınız

Ne? Geriye sahipsin. trueolarak değerlendirilir 1ve falseolarak değerlendirilir 0. C yerli boole türlerini bilmiyor, sadece ints.
djechlin

C'de, ilişkisel ve eşitlik işleçleri, tür veya intdeğer içeren sonuçlar verir . C (gerçek boolean türü var bir makro ile, tanımlanmış , ama bu sadece yoktu, C99 ile eklendi değil yeni türünü kullanmak için operatörlerin semantiğini değiştirin.01_Boolbool<stdbool.h>
Keith Thompson

@djechlin: 1999 standardı olarak, Cı- yapar doğal bir Boole türü vardır. Denir _Boolve <stdbool.h>vardır #define bool _Bool.
Keith Thompson

@ KeithThompson, 1 == 1olarak değerlendirilme konusunda haklısınız int. Düzenlenen.
Ayakkabı

3

DOĞRU'nun eşit olduğu kesin değeri bilmiyoruz ve derleyicilerin kendi tanımları olabilir. Privode yaptığınız şey derleyicinin dahili tanımını kullanmaktır. İyi programlama alışkanlıklarınız varsa bu her zaman gerekli değildir, ancak bazı kötü kodlama stilleriyle ilgili sorunları önleyebilir, örneğin:

if ((a> b) == DOĞRU)

TRUE değerini manüel olarak 1 olarak tanımlarsanız bu bir felaket olabilirken, TRUE iç değeri başka bir değerdir.


C'de, >operatör daima true için 1, false için 0 verir. Herhangi bir C derleyicisinin bunu yanlış anlama olasılığı yoktur. Eşitlik karşılaştırmaları TRUEve FALSEzayıf üslup; yukarıdakiler daha net olarak yazılmıştır if (a > b). Ancak farklı C derleyicilerinin gerçeği ve yanlışları farklı şekilde ele alabileceği fikri yanlıştır.
Keith Thompson

2
  1. Liste öğesi

Tipik olarak C Programlama Dili'nde 1, true olarak ve 0, false olarak tanımlanır. Bu nedenle aşağıdakileri neden sıklıkla görüyorsunuz:

#define TRUE 1 
#define FALSE 0

Ancak, koşullu bir ifadede 0'a eşit olmayan herhangi bir sayı doğru olarak değerlendirilir. Bu nedenle aşağıdakileri kullanarak:

#define TRUE (1==1)
#define FALSE (!TRUE)

Yanlış olanı yanlış olana eşit yaparak onu güvenli bir şekilde oynamaya çalıştığınızı açıkça gösterebilirsiniz.


4
Ben buna "güvenli oynamak" demem - bunun yerine kendinize yanlış bir güvenlik duygusu veriyorsunuz.
dodgethesteamroller
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.