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ć.
int
. Byłbym jednak bardzo zdziwiony, gdyby w ogóle coś zmieniło w nowoczesnym kompilatorze.Od programisty C:
A
const
to po prostu zmienna, której zawartości nie można zmienić.#define name value
jednak jest to polecenie preprocesora, które zastępuje wszystkie wystąpienianame
zvalue
.Na przykład, jeśli ty
#define defTest 5
, wszystkie wystąpieniadefTest
w twoim kodzie zostaną zastąpione przez5
podczas kompilacji.źródło
Ważne jest, aby zrozumieć różnicę między instrukcjami #define i const, które nie są przeznaczone do tych samych rzeczy.
const
const
służy do generowania obiektu z żądanego typu, który po zainicjowaniu będzie stały. Oznacza to, że jest to obiekt w pamięci programu i może być używany tylko do odczytu. Obiekt jest generowany przy każdym uruchomieniu programu.#define
#define
jest używany w celu ułatwienia czytelności kodu i przyszłych modyfikacji. Używając definicji, maskujesz tylko wartość za nazwą. Dlatego podczas pracy z prostokątem można zdefiniować szerokość i wysokość za pomocą odpowiednich wartości. Wtedy w kodzie będzie łatwiejszy do odczytania, ponieważ zamiast liczb pojawią się nazwy.Jeśli później zdecydujesz się zmienić wartość szerokości, będziesz musiał zmienić ją tylko w definicji zamiast nudnego i niebezpiecznego wyszukiwania / zamiany w całym pliku. Podczas kompilacji preprocesor zastąpi wszystkie zdefiniowane nazwy wartościami w kodzie. Dzięki temu nie musisz tracić czasu na ich używanie.
źródło
Oprócz komentarzy innych osób, błędy przy użyciu
#define
są bardzo trudne do debugowania, ponieważ preprocesor przechwytuje je przed kompilatorem.źródło
Ponieważ dyrektywy preprocesora są źle widziane, sugeruję użycie pliku
const
. Nie można określić typu z preprocesorem, ponieważ dyrektywa preprocesora jest rozwiązana przed kompilacją. Cóż, możesz, ale coś takiego:#define DEFINE_INT(name,value) const int name = value;
i używaj go jako
DEFINE_INT(x,42)
który byłby postrzegany przez kompilator jako
const int x = 42;
Możesz, zobacz mój pierwszy fragment.
Generalnie posiadanie
const
dyrektywy zamiast preprocesora pomaga w debugowaniu, nie tak bardzo w tym przypadku (ale nadal pomaga).Obie są równie wydajne. Powiedziałbym, że makro może być potencjalnie bezpieczniejsze, ponieważ nie można go zmienić w czasie wykonywania, podczas gdy zmienna może.
źródło
const ...
zamiast makra?pre-processor directives are frowned upon
[potrzebne źródło]Użyłem już wcześniej #define, aby pomóc w utworzeniu większej liczby metod z jednej metody, na przykład jeśli mam coś takiego.
// This method takes up to 4 numbers, we don't care what the method does with these numbers. void doSomeCalculationWithMultipleNumbers:(NSNumber *)num1 Number2:(NSNumber *)num2 Number3:(NSNumber *)num23 Number3:(NSNumber *)num3;
Ale chcę też mieć metodę, która przyjmuje tylko 3 liczby i 2 liczby, więc zamiast pisać dwie nowe metody, zamierzam użyć tej samej, używając #define.
#define doCalculationWithFourNumbers(num1, num2, num3, num4) \ doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), (num4)) #define doCalculationWithThreeNumbers(num1, num2, num3) \ doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), nil) #define doCalculationWithTwoNumbers(num1, num2) \ doSomeCalculationWithMultipleNumbers((num1), (num2), nil, nil)
Myślę, że to całkiem fajna rzecz, wiem, że możesz od razu przejść do metody i po prostu wstawić zero w przestrzeniach, których nie chcesz, ale jeśli budujesz bibliotekę, jest to bardzo przydatne. Tak też jest
NSLocalizedString(<#key#>, <#comment#>) NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>) NSLocalizedStringFromTableInBundle(<#key#>, <#tbl#>, <#bundle#>, <#comment#>)
są skończone.
Podczas gdy nie wierzę, że można to zrobić za pomocą stałych. Ale stałe mają swoje zalety w stosunku do #define, na przykład nie można określić typu za pomocą #define, ponieważ jest to dyrektywa preprocesora, która jest rozwiązywana przed kompilacją, a jeśli pojawi się błąd z #define, trudniej jest wtedy debugować stałe. Oba mają zalety i wady, ale powiedziałbym, że wszystko zależy od programisty, z którym zdecydowałeś się użyć. Napisałem bibliotekę z oboma, używając #define, aby robić to, co pokazałem, i stałych do deklarowania zmiennych stałych, na których muszę określić typ.
źródło