Po pierwsze stwierdziłem, że nie można zdefiniować typu stałej za pomocą #define. Dlaczego tak jest?
Dlaczego co? To nie prawda:
#define MY_INT_CONSTANT ((int) 12345)
Po drugie, czy są jakieś zalety używania jednego z nich nad drugim?
Tak. #define
definiuje makro, które jest zastępowane jeszcze przed rozpoczęciem kompilacji. const
po prostu modyfikuje zmienną, aby kompilator oznaczył błąd, jeśli spróbujesz go zmienić. Są konteksty, w których możesz użyć a, #define
ale nie możesz użyć const
(chociaż staram się znaleźć taki, który używa najnowszego clang). Teoretycznie const
zajmuje miejsce w pliku wykonywalnym i wymaga odniesienia do pamięci, ale w praktyce jest to nieistotne i może zostać zoptymalizowane przez kompilator.
const
s są znacznie bardziej przyjazne dla kompilatorów i debugerów niż #define
s. W większości przypadków jest to nadrzędny punkt, który należy wziąć pod uwagę przy podejmowaniu decyzji, którego z nich użyć.
Pomyślałem o kontekście, w którym możesz użyć, #define
ale nie const
. Jeśli masz stałą, której chcesz użyć w wielu .c
plikach, #define
po prostu umieść ją w nagłówku. Z a const
musisz mieć definicję w pliku C i
const int MY_INT_CONST = 12345;
extern const int MY_INT_CONST;
w nagłówku. MY_INT_CONST
nie może być używany jako rozmiar tablicy o zasięgu statycznym lub globalnym w żadnym pliku C, z wyjątkiem tego, w którym jest zdefiniowana.
Jednak w przypadku stałych całkowitych można użyć rozszerzenia enum
. W rzeczywistości Apple robi to prawie zawsze. Ma to wszystkie zalety zarówno #define
s, jak i const
s, ale działa tylko dla stałych całkowitych.
enum
{
MY_INT_CONST = 12345,
};
Wreszcie, który sposób jest bardziej wydajny i / lub bezpieczniejszy?
#define
jest bardziej wydajne w teorii, chociaż, jak powiedziałem, nowoczesne kompilatory prawdopodobnie zapewniają, że różnica jest niewielka. #define
jest bezpieczniejszy, ponieważ próba przypisania do niego zawsze jest błędem kompilatora
#define FOO 5
FOO = 6;
const
s można oszukać, aby zostać przypisanym do, chociaż kompilator może generować ostrzeżenia:
const int FOO = 5;
(int) FOO = 6;
W zależności od platformy przypisanie może nadal zakończyć się niepowodzeniem w czasie wykonywania, jeśli stała jest umieszczona w segmencie tylko do odczytu i jest oficjalnie niezdefiniowanym zachowaniem zgodnie ze standardem C.
Osobiście w przypadku stałych całkowitych zawsze używam enum
s dla stałych innych typów, używam const
chyba, że mam bardzo dobry powód, aby tego nie robić.