"Statik sabit" ve "# tanım" vs "enum"


585

Hangisi C'de aşağıdaki ifadeler arasında kullanmak daha iyidir?

static const int var = 5;

veya

#define var 5

veya

enum { var = 5 };

35
İlginçtir, bu neredeyse stackoverflow.com/questions/1637332/static-const-vs-define ile aynı soru . Tek fark, bu sorunun C ++ ile ilgili olması ve bu C ile ilgili olmasıdır. Cevabım C ++ 'a özgü olduğu için, onları aynı kılmadığını söylüyorum, ancak diğerleri katılmayabilir.
TED

53
Kesinlikle aynı değil. Uyumluluk nedenleriyle C ++ 'ın C sözdizimine izin verdiği birçok alan vardır. Bu gibi durumlarda, "X yapmanın en iyi yolu nedir" gibi soruların C ++ 'da farklı cevapları olacaktır. Örneğin nesne başlatma.
MSalters


Bu görüşe dayalı değil mi? Her birinin farklı bir amacı var
Sam Hammamy

1
@RobertSsupportsMonicaCellio, Evet. Samimiyetiniz için teşekkür ederiz
Vijay

Yanıtlar:


690

Değer için neye ihtiyacınız olduğuna bağlıdır. Siz (ve şu ana kadar herkes) üçüncü alternatifi atladınız:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

İsim seçimi ile ilgili sorunları göz ardı ederek:

  • Etrafta bir işaretçi geçirmeniz gerekiyorsa (1) kullanmanız gerekir.
  • Görünüşe göre (2) bir seçenek olduğu için, işaretçileri geçmenize gerek yok.
  • Hem (1) hem de (3) hata ayıklayıcının sembol tablosunda bir simge vardır - bu hata ayıklamayı kolaylaştırır. (2) 'nin bir sembolü olmayacağı ve bunun ne olduğunu merak etmen daha olasıdır.
  • (1) küresel kapsamdaki diziler için bir boyut olarak kullanılamaz; hem (2) hem de (3) olabilir.
  • (1) işlev kapsamındaki statik diziler için boyut olarak kullanılamaz; hem (2) hem de (3) olabilir.
  • C99 altında, bunların tümü yerel diziler için kullanılabilir. Teknik olarak, (1) 'in kullanılması bir VLA'nın (değişken uzunluklu dizi) kullanımını ima eder, ancak' var 'tarafından referans verilen boyut elbette 5 boyutunda sabitlenir.
  • (1) anahtar ifadeleri gibi yerlerde kullanılamaz; hem (2) hem de (3) olabilir.
  • (1) statik değişkenleri başlatmak için kullanılamaz; hem (2) hem de (3) olabilir.
  • (2) önişlemci tarafından kullanıldığı için değiştirilmesini istemediğiniz kodu değiştirebilir; (1) ve (3) 'ün böyle beklenmedik yan etkileri olmayacaktır.
  • Ön işlemcide (2) ayarlanmış olup olmadığını tespit edebilirsiniz; ne (1) ne de (3) buna izin vermez.

Yani, çoğu bağlamda, alternatiflere göre 'enum'u tercih edin. Aksi takdirde, ilk ve son mermi noktalarının kontrol edici faktörler olması muhtemeldir - ve her ikisini de aynı anda tatmin etmeniz gerekiyorsa daha fazla düşünmeniz gerekir.

C ++ hakkında soru soruyorsanız, (1) seçeneğini - statik sabit - her seferinde kullanırsınız.


111
harika bir liste! Bunun bir dezavantajı ([C99] 6.7.2.2/3) enumolarak uygulanmasıdır int. A, #defineimzasız ve uzun ekleri Uve Lsonekleri belirtmenizi constsağlar ve bir tür vermenizi sağlar. enumnormal tür dönüşümlerde sorunlara neden olabilir.
Gauthier

37
(2) insanlar DAİMA tip güvenliğinden şikayet ederler. Neden sadece "#define var ((int) 5)" kullanmıyorsunuz ve tanımlamakla tip güvenliğiniz var.
Ingo Blackman

6
@RedX: Alanın endişe etmesi için çok tuhaf bir ortamda olmanız gerekir. Bununla birlikte, ne ekstra ne enumde #definekendi başına kullanır. Değer, veri segmentinde veya yığınta veya yığın üzerinde depolama alanı olarak ayrılmak yerine nesne kodunda talimatların bir parçası olarak görünür. İçin yer ayırmış olacaksınız static const int, ancak bir adres almazsanız derleyici alanı optimize edebilir.
Jonathan Leffler

15
enumS (ve static const) için başka bir 'oy' : değiştirilemezler. Bir defineolabilir #undefined' burada bir enumve static constbelirli bir değere sabitlenir.
Daan Timmer

15
@QED: Hayır, teşekkür ederim. Basit bir sabit parantez dışında güvenlidir. Ya da, meşru bir şekilde derlenmesi beklenen bir programın 5'i parantez içinde değiştirmeyerek nasıl değiştirileceğini gösterin. İşlev tarzı bir makronun argümanı olsaydı veya ifadede herhangi bir operatör varsa, parantezleri dahil etmemiş olsaydım beni suçlamak doğru olurdu. Ama burada durum böyle değil.
Jonathan Leffler

282

Genel konuşma:

static const

Çünkü kapsama saygı duyar ve tip güvenlidir.

Görebildiğim tek uyarı: değişkenin komut satırında tanımlanmasını istiyorsanız. Hala bir alternatif var:

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

Mümkün olduğunda, makrolar / üç nokta yerine, güvenli bir alternatif kullanın.

Gerçekten bir makroya (örneğin, istediğiniz __FILE__veya __LINE__) ihtiyacınız varsa, makronuzu ÇOK dikkatli bir şekilde adlandırmanız daha iyi olur: Adlandırma kuralında Boost , projenin adından başlayarak tüm büyük harfleri önerir (burada BOOST_ ), kitaplığı incelerken bunun (genellikle) ardından belirli bir alanın (kitaplığın) ardından anlamlı bir adla geldiğini göreceksiniz.

Genellikle uzun isimler yapar :)


2
Kabul edildi - ayrıca #define ile önişlemci sözdiziminin farkında olmadığından genel bir kod yönetimi tehlikesi vardır.
NeilDurant

10
# İf #fdef'den daha iyi kullanmak daha iyidir, ama aksi halde katılıyorum. +1.
Tim Post

58
Bu standart C ++ evanjelizmidir. Aşağıdaki cevap, seçeneklerin gerçekte ne anlama geldiğini açıklamada çok daha nettir. Özellikle: Ben sadece "statik const" ile ilgili bir sorun vardı. Birisi bunu bir başlık dosyasında yaklaşık 2000 "sabit" tanımlamak için kullandı. Daha sonra bu başlık dosyası yaklaşık 100 ".c" ve ".cpp" dosyalarına dahil edildi. => 8 "consts" için bayt. Harika. Evet, referans verilmemiş consts kaldırmak için bir linker kullanabilirsiniz biliyorum, ama sonra bu hala size ARE hangi "consts" bırakır. Bu cevapta sorun nedir.
Ingo Blackman

2
@IngoBlackman: İyi bir derleyici ile sadece staticadresi alınmış olanlar kalmalıdır; ve adres alınırsa, bir #defineveya enum(adres yok) kullanamazdım ... bu yüzden hangi alternatifin kullanılabileceğini göremiyorum. "Derleme süresi değerlendirmesi" ile başa çıkmak, extern constbunun yerine arıyor olabilir .
Matthieu M.

15
@Tim Mesaj: #ifover tercih olabilir #ifdefboolean bayrakları için, ancak bu durumda o imkansız tanımlamak kılacak varşekilde 0komut satırından. Bu durumda, yasal bir değer #ifdefolduğu sürece daha mantıklıdır . 0var
Maarten

108

C olarak, özellikle? C'de doğru cevap: kullanın #define(veya uygunsa,enum )

Bir constnesnenin kapsam ve yazma özelliklerine sahip olmak faydalı olsa da, gerçekteconst C'deki nesnelerde (C ++ yerine) gerçek sabitler sabit değildir ve bu nedenle çoğu pratik durumda genellikle işe yaramaz.

Bu nedenle, C'de seçim, sabitinizi nasıl kullanmayı planladığınıza göre belirlenmelidir. Örneğin, bir const intnesneyi caseetiket olarak kullanamazsınız (makro çalışırken). Bir const intnesneyi bit alanı genişliği olarak kullanamazsınız (makro çalışırken). C89 / 90'da constbir dizi boyutu belirtmek için bir nesne kullanamazsınız (bir makro çalışırken). C99'da bile, VLAconst olmayan bir öğeye ihtiyacınız olduğunda bir dizi boyutu belirtmek için bir nesneyi kullanamazsınız .

Bu sizin için önemliyse, seçiminizi belirler. Çoğu zaman, kullanmaktan başka seçeneğiniz olmaz#define C'de başka seçeneğiniz olmayacaktır. Ve C - 'de gerçek sabitler üreten başka bir alternatifi unutmayın enum.

C ++ constnesnelerinde gerçek sabitler vardır, bu yüzden C ++ 'da constvaryantı tercih etmek neredeyse her zaman daha iyidir ( staticC ++' da açıkça gerek yoktur ).


6
"const int nesnesini bir vaka etiketi olarak kullanamazsınız (bir makro çalışırken)" ---> Bu ifadeyle ilgili olarak, çalışma durumunda C'de bir const int değişkenini test ettim ....
john

8
@john: Eh, test ettiğiniz kodu sağlamanız ve belirli derleyiciyi adlandırmanız gerekir. const intVaka etiketlerinde nesne kullanmak , C dilinin tüm sürümlerinde yasa dışıdır. (Tabii ki, derleyiciniz standart olmayan C ++ benzeri bir dil uzantısı olarak desteklemekte serbesttir.)
AnT

11
“... ve bu nedenle çoğu pratik durumda işe yaramazlar .” Katılmıyorum. Adı sabit bir ifade olarak kullanmanız gerekmediği sürece son derece kullanışlıdırlar. C'deki "sabit" kelimesi, derleme zamanında değerlendirilebilen bir şey anlamına gelir; constsalt okunur anlamına gelir. const int r = rand();tamamen yasaldır.
Keith Thompson

C ++ 'da, veya gibi kaplarla özel constexprolarak karşılaştırıldığında daha iyidir . conststlarraybitset
Mayukh Sarkar

1
@john bir tanesinde switch()değil, ifadede test etmiş olmalısınız case. Ben de buna yakalandım ☺
Hi-Angel

32

Arasındaki fark static const ve #defineolduğu önceki kullanımları bellek ve depolama için daha sonra kullanmaz bellek. İkinci olarak, bir #defineadresin adresini geçiremezken, a static const. Aslında, hangi koşul altında olduğumuza bağlı olarak, bu ikisi arasından birini seçmemiz gerekiyor. Her ikisi de farklı koşullar altında en iyi durumdadır. Lütfen birinin diğerinden daha iyi olduğunu varsaymayın ... :-)

Durum böyle olsaydı, Dennis Ritchie en iyisini yalnız tutacaktır ... hahaha ... :-)


6
Hafızadan bahsetmek için +1, bazı gömülü sistemlerde hala bu kadar çok şey yok, ancak muhtemelen statik consts kullanmaya başlayacağım ve gerekirse #defines olarak değiştireceğim.
fluffyben

3
Sadece test ettim. Aslında, const int #define veya enum ile karşılaştırıldığında ek bellek kullanır. Gömülü sistemleri programladığımız için ek bellek kullanımını göze alamayız. Yani, #define veya enum kullanmaya geri döneceğiz.
Davide Andrea

2
Pratik olarak a'nın consthafızayı kullandığı doğru değildir (artık) . GCC (4.5.3 ve birkaç yeni sürümle test edilmiştir) const int-O3 kullanırken kolayca kodunuzdaki doğrudan değişmez değeri optimize eder . Dolayısıyla, düşük RAM katıştırılmış geliştirme (örneğin AVR) yaparsanız, GCC veya başka bir uyumlu derleyici kullanıyorsanız C consts'ı güvenle kullanabilirsiniz. Ben test etmedim ama Clang aynı şeyi btw yapmasını bekliyoruz.
Raphael

19

C'de #defineçok daha popüler. Bu değerleri dizi boyutlarını bildirmek için kullanabilirsiniz, örneğin:

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

ANSI C static constbildiğim kadarıyla bu bağlamda kullanmanıza izin vermiyor . C ++ 'da bu durumlarda makrolardan kaçınmalısınız. Yazabilirsin

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

ve hatta staticiç bağlantı constzaten [sadece C ++ ile] ima edildiği için bile dışarıda kalır .


1
"İç bağlantı" ile ne demek istiyorsun? Ben olabilir const int MY_CONSTANT = 5;tek dosyada ve bunu erişmek extern const int MY_CONSTANT;başka. Standartta (en azından C99) constvarsayılan davranışı değiştirmeyle ilgili hiçbir bilgi bulamadım "6.2.2: 5 Bir nesne için tanımlayıcının bildirimi dosya kapsamına sahipse ve depolama sınıfı belirticisi yoksa, bağlantısı harici" dir.
Gauthier

@Gauthier: Üzgünüm, bunun için. Ben "zaten C ++ dilinde const tarafından ima edilir" demeliydim. Bu C ++ 'a özgüdür.
sellibitze

@ sellibitze tonlarca OPINION yerine yol boyunca bazı argümanları görmek güzel .
Paul

1
C99'dan itibaren, ikinci pasajınız yasaldır. barbir VLA (değişken uzunluk dizisi); derleyici, uzunluğu sabitmiş gibi kod üretebilir.
Keith Thompson

14

constC'nin bir başka dezavantajı , değeri bir başkasını başlatırken kullanamamanızdır const.

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

Derleyici sabit olarak görmediğinden bu bile bir const ile çalışmaz:

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

constBu durumlarda yazılan kullanmaktan mutluluk duyarım , aksi takdirde ...


5
Oyuna biraz geç kaldım, ama bu soru başka bir soruda ortaya çıktı. Neden static uint8_t const ARRAY_SIZE = 16;birdenbire derlenmeyeceğinizi takip etmek biraz zor olabilir, özellikle de #define ARRAY_SIZE 256karışık bir başlık ağında on kat derinlere gömüldüğünde. Tüm büyük harflerin isminin ARRAY_SIZEbelada olduğunu sorar. ALL_CAPS'u makrolar için ayırın ve hiçbir zaman ALL_CAPS formunda olmayan bir makro tanımlamayın.
David Hammen

@David: Takip edeceğim sağlam tavsiyeler.
Gauthier

1
4 yıl sonra neden "yuvalayamadığım" için bana çok zaman kazandınız const. Bu daha fazla iptal edilebilir!
Plouff

11

Eğer ondan kurtulabilirsen, static const , bir çok avantajı var. Normal kapsam ilkelerine uyar, bir hata ayıklayıcıda görünür ve genellikle değişkenlerin uyduğu kurallara uyar.

Bununla birlikte, en azından orijinal C standardında, aslında bir sabit değildir. Eğer kullanırsanız #define var 5, yazabilir int foo[var];bir deklarasyon olarak, ancak bir derleyici uzantısı" olarak haricinde (bunu yapamaz static const int var = 5;. Bu ++, C durum böyle değildir static constversiyonu her yerde kullanılabilir#define versiyonu kutu ve ben buna inanıyorum C99 için de geçerlidir.

Bununla birlikte, asla bir #definesabiti küçük harfli isimle adlandırmayın. Çeviri biriminin sonuna kadar bu adın olası kullanımını geçersiz kılacaktır. Makro sabitleri, geleneksel olarak tüm büyük harfler, belki de bir önek ile kendi ad alanı etkili bir şekilde olmalıdır.


6
Ne yazık ki, C99'da durum böyle değil. constC99'da hala gerçek bir sabit değil. Dizi boyutunu constC99'da bir ile bildirebilirsiniz , ancak yalnızca C99 Değişken Uzunluk Dizilerini desteklediğinden. Bu nedenle, sadece VLA'lara izin verilen yerlerde çalışacaktır. Örneğin, C99'da bile, a öğesindeki constbir üye dizisinin boyutunu bildirmek için yine de kullanamazsınız struct.
AnT 0:25

C99'un bunu yapmanıza izin vermeyeceği doğru olsa da, GCC (4.5.3 ile test edilmiştir), const intbir C ++ const veya makroymuş gibi bir boyutu olan dizileri mükemmel bir şekilde başlatmanıza izin verecektir . GCC'nin standarttan bu sapmasına bağlı kalmak isteyip istemediğiniz elbette seçiminizdir, GCC veya Clang'dan başka bir derleyici kullanmayı gerçekten düşünmedikçe, kişisel olarak onunla birlikte giderim, ikincisi burada aynı özelliğe sahiptir (Clang ile test edilmiştir) 3.7).
Raphael

7

#Define yerine const kullanmak DAİMA tercih edilir. Çünkü const derleyici tarafından işlenir ve #define önişlemci tarafından işlenir. Bu #define kendisi kodun bir parçası değildir (kabaca konuşursak).

Misal:

#define PI 3.1416

PI sembolik ismi derleyiciler tarafından asla görülemez; kaynak kod bir derleyiciye ulaşmadan önce önişlemci tarafından kaldırılabilir. Sonuç olarak, sembol tablosuna PI adı girilemeyebilir. Sabitin kullanımını içeren derleme sırasında bir hata alırsanız bu kafa karıştırıcı olabilir, çünkü hata mesajı PI değil 3.1416'ya işaret edebilir. PI, yazmadığınız bir başlık dosyasında tanımlanmış olsaydı, 3.1416'nın nereden geldiğine dair hiçbir fikriniz olmazdı.

Bu sorun sembolik bir hata ayıklayıcıda da ortaya çıkabilir, çünkü yine programladığınız ad sembol tablosunda olmayabilir.

Çözüm:

const double PI = 3.1416; //or static const...

6

#define var 5gibi şeyleriniz varsa size sorun çıkarır mystruct.var.

Örneğin,

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

Önişlemci onun yerini alacak ve kod derlenmeyecektir. Bu nedenle, geleneksel kodlama stili, tüm sabit #defines'lerin çatışmayı önlemek için büyük harfler kullanmasını önerir .


6

Bir farkı göstermek için hızlı test programı yazdım:

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

Bu, aşağıdaki hatalar ve uyarılarla derlenir:

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

Define bir uyarı verdiğinde enum'un hata verdiğini unutmayın.


4

Tanım

const int const_value = 5;

her zaman sabit bir değer tanımlamaz. Bazı derleyiciler (örneğin tcc 0.9.26 ) sadece "const_value" adıyla tanımlanan belleği ayırır. "Const_value" tanımlayıcısını kullanarak bu belleği değiştiremezsiniz. Ancak yine de belleği başka bir tanımlayıcı kullanarak değiştirebilirsiniz:

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

Bu tanım

#define CONST_VALUE 5

hiçbir şekilde değiştirilemeyen sabit bir değer tanımlamanın tek yoludur.


8
İşaretçi kullanarak sabit bir değeri değiştirmek tanımsız bir davranıştır. Oraya gitmek istiyorsanız #define, makine kodunu düzenleyerek de değiştirebilirsiniz.
ugoren

Kısmen haklısın. Kodu Visual Studio 2012 ile test ettim ve basıyor 5. Ancak #definebir önişlemci makrosu olduğu için değişiklik yapılamaz . İkili programda mevcut değildir. Eğer CONST_VALUEkullanılan tüm yerleri değiştirmek isterse, bunu tek tek yapmak zorundaydı.
user2229691

3
@ugoren: Yazdığınız Varsayalım #define CONST 5sonra, if (CONST == 5) { do_this(); } else { do_that(); }ve derleyici ortadan kaldırır elsedalı. Makine kodunu CONST6 olarak değiştirmek için düzenlemeyi nasıl öneriyorsunuz ?
Keith Thompson

@KeithThompson, asla kolay ve güvenilir bir şekilde yapılabileceğini söylemedim. Sadece bu #definekurşun geçirmez değil.
ugoren

3
@ugoren: Demek istediğim, "makine kodunun düzenlenmesi" nin a değerini değiştirmenin etkisini çoğaltmanın mantıklı bir yolu olmadığıdır #define. Bunu yapmanın tek gerçek yolu kaynak kodunu düzenlemek ve yeniden derlemektir.
Keith Thompson

4

Her ne kadar soru tamsayılarla ilgili olsa da, sabit bir yapıya veya dizgiye ihtiyacınız varsa #define ve enums'un işe yaramaz olduğunu belirtmek gerekir. Bunların her ikisi de genellikle işaretçi olarak işlevlere geçirilir. (Dizelerle gereklidir; yapılarla çok daha verimlidir.)

Tamsayılara gelince, çok sınırlı belleğe sahip gömülü bir ortamdaysanız, sabitin nerede depolandığı ve ona erişimin nasıl derlendiği konusunda endişelenmeniz gerekebilir. Derleyici çalışma zamanında iki const ekleyebilir, ancak derleme zamanında iki #define ekleyebilir. Bir #define sabiti bir veya daha fazla MOV [acil] komutuna dönüştürülebilir, bu sabitin program belleğinde etkili bir şekilde saklandığı anlamına gelir. Bir const sabiti, veri belleğindeki .const bölümünde saklanır. Harvard mimarisine sahip sistemlerde, küçük olmalarına rağmen performans ve bellek kullanımında farklılıklar olabilir. İç döngülerin sert çekirdek optimizasyonu için önemli olabilirler.


3

"Her zaman en iyisi" için bir cevap olduğunu düşünmeyin, ancak Matthieu'nun dediği gibi

static const

güvenli tiptir. #defineBununla birlikte , en büyük evcil hayvanım , Visual Studio'da hata ayıklama sırasında değişkeni izleyememeniz. Sembolün bulunamaması hatası verir.


1
"değişkeni izleyemezsiniz" Doğru, bu bir değişken değil. Değişmiyor, neden izlemelisin? Etiketi arayarak kullanıldığı her yerde bulabilirsiniz. Neden #define izlemeniz gerekiyor (hatta istemesin)?
Marshall Eubanks

3

Bu arada, #defineuygun kapsam belirleme sağlayan ancak "gerçek" sabit gibi davranan bir alternatif "enum" dur. Örneğin:

enum {number_ten = 10;}

Çoğu durumda, numaralandırılmış türleri tanımlamak ve bu türlerden değişkenler oluşturmak yararlıdır; bu yapılırsa, hata ayıklayıcılar numaralandırma adlarına göre değişkenleri görüntüleyebilir.

Bununla birlikte, bununla ilgili önemli bir uyarı: C ++ 'da, numaralandırılmış türlerin tamsayılarla sınırlı uyumluluğu vardır. Örneğin, varsayılan olarak, bunlarda aritmetik yapılamaz. Ben enums için meraklı bir varsayılan davranış olduğunu düşünüyorum; "sıkı enum" türü olması güzel olurdu, C ++ genellikle C ile uyumlu olma arzusu göz önüne alındığında, bir "enum" türü varsayılan davranış tamsayı ile değiştirilebilir olması gerektiğini düşünüyorum.


1
C de, numaralandırma sabitleri her zaman inttürdedir, bu nedenle "enum hack" diğer tamsayı türleriyle kullanılamaz. (Numaralandırma türü , zorunlu olarak değil, bazı uygulama tanımlı tamsayı türüyle uyumludur int, ancak bu durumda tür anonimdir, bu nedenle önemli değildir.)
Keith Thompson

@KeithThompson: Yukarıdakileri yazdığım için, bir derleyici intnumaralandırma türünde bir değişkenden başka bir tür atadığında (derleyicilerin yapmasına izin verilir) MISRA-C'nin squawk okuyacağını ve böyle bir değişkene atanmaya çalıştığını okudum kendi numaralandırmasının bir üyesi. Standart komitelerinin belirtilen semantiklerle tamsayı türlerini bildirmenin taşınabilir yollarını eklemesini isterdim. HERHANGİ BİR platform, charboyutuna bakılmaksızın , derleyici çok sayıda AND R0,#0xFFFFveya eşdeğer talimat eklemek zorunda olsa bile, örneğin 65536'yı saran bir tür bildirebilmelidir .
supercat

Sen kullanabilirsiniz uint16_tbir numaralandırma türü değil elbette olsa. Kullanıcının belirli bir numaralandırma türünü temsil etmek için kullanılan tamsayı türünü belirtmesine izin vermek güzel olurdu, ancak tek tek değerler için bir typedeffor uint16_tve #defines serisi ile aynı etkinin çoğunu elde edebilirsiniz .
Keith Thompson

1
@ KeithThompson: Tarihsel nedenlerden ötürü, bazı platformların 2U < -1Ldoğru ve diğerlerini yanlış olarak değerlendireceğinden ve şu anda bazı platformların imzalanmış uint32_tve int32_timzalanmış olarak bir karşılaştırma yapmasıyla şaşırdık. bazıları imzasızdır, ancak bu Komite, anlambilimi tüm derleyicilerde tutarlı olacak türleri içeren C'ye yukarı doğru uyumlu bir halef tanımlayamayacağı anlamına gelmez.
supercat

1

Basit bir fark:

Ön işleme zamanında sabit, değeri ile değiştirilir. Bu nedenle, bir tanımlamaya dereference operatörünü uygulayamazsınız, ancak dereference operatörünü bir değişkene uygulayabilirsiniz.

Tahmin edeceğiniz gibi, tanım statik sabitten daha hızlıdır.

Örneğin:

#define mymax 100

yapamazsın printf("address of constant is %p",&mymax);.

Ama sahip olmak

const int mymax_var=100

yapabilirsin printf("address of constant is %p",&mymax_var);.

Daha açık olmak gerekirse, tanım, ön işleme aşamasında değeri ile değiştirilir, bu nedenle programda depolanan herhangi bir değişkenimiz yoktur. Sadece tanımın kullanıldığı programın metin bölümündeki koda sahibiz.

Ancak, statik sabit için bir yere tahsis edilen bir değişkenimiz var. Gcc için, statik sabit programın metin bölümüne ayrılır.

Yukarıda, referans operatörü hakkında bilgi vermek istedim, bu yüzden referansı referansla değiştirin.


1
Cevabınız çok yanlış. Bu C ile ilgili, cevabınız constniteleyici için çok farklı semantiğe sahip C ++ ile ilgilidir . C, enum-sabitleri dışında sembolik sabitlere sahip değildir . A const intbir değişkendir. Dil ve belirli uygulamaları da karıştırıyorsunuz. Nesnenin nereye yerleştirileceğine gerek yoktur. Ve gcc için bile doğru değildir: tipik olarak bölüme constnitelikli değişkenler yerleştirir .rodata. Ancak bu, hedef platforma bağlıdır. Ve operatörün adresi demek istiyorsun &.
Bu site için çok dürüst

0

MBF16X üzerinde üretilen montajcı koduna baktık ... Her iki varyant da aritmetik işlemler için aynı kodla sonuçlanır (örneğin, ADD Immediate).

Yani const intiken tip kontrolü için tercih edilmektedir #defineeski tarzıdır. Belki derleyiciye özgüdür. Ürettiğiniz montajcı kodunu kontrol edin.


-1

Ben haklı olup olmadığından emin değilim ama benim görüşüme göre #defined değeri çağırmak herhangi bir normalde bildirilen değişken (veya const değeri) çağırmak çok daha hızlıdır. Program çalışırken ve normal olarak bildirilen bir değişken kullanması gerektiğinde, bu değişkeni almak için bellekte tam bir yere atlaması gerekir.

Tersine, #defined değerini kullandığında , programın ayrılmış bir belleğe atlaması gerekmez, sadece değeri alır. Eğer #define myValue 7ve program çağırıyorsa myValue, sadece aradığı zamanki gibi davranır 7.

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.