Во-первых, я обнаружил, что невозможно определить тип константы с помощью #define, почему?
Почему что? Это неправда:
#define MY_INT_CONSTANT ((int) 12345)
Во-вторых, есть ли преимущества в использовании одного из них перед другим?
Да. #define
определяет макрос, который заменяется еще до начала компиляции. const
просто изменяет переменную, чтобы компилятор пометил ошибку, если вы попытаетесь ее изменить. Есть контексты, в которых вы можете использовать a, #define
но не можете использовать const
(хотя я изо всех сил пытаюсь найти его, используя последнюю версию clang). Теоретически a const
занимает место в исполняемом файле и требует ссылки на память, но на практике это несущественно и может быть оптимизировано компилятором.
const
s гораздо более дружелюбны к компилятору и отладчику, чем #define
s. В большинстве случаев это главный момент, который вы должны учитывать при принятии решения, какой из них использовать.
Просто подумайте о контексте, в котором вы можете использовать, #define
но не можете const
. Если у вас есть константа, которую вы хотите использовать во многих .c
файлах, #define
вы просто вставляете ее в заголовок. С a у const
вас должно быть определение в файле C и
const int MY_INT_CONST = 12345;
extern const int MY_INT_CONST;
в шапке. MY_INT_CONST
не может использоваться как размер статического или глобального массива области видимости в любом файле C, кроме того, в котором он определен.
Однако для целочисленных констант вы можете использовать расширение enum
. Фактически, это то, что Apple делает почти всегда. Это имеет все преимущества как #define
s, так и const
s, но работает только для целочисленных констант.
enum
{
MY_INT_CONST = 12345,
};
Наконец, какой способ более эффективен и / или безопаснее?
#define
теоретически более эффективен, хотя, как я уже сказал, современные компиляторы, вероятно, обеспечивают небольшую разницу. #define
более безопасен тем, что попытка присвоить ему всегда является ошибкой компилятора
#define FOO 5
FOO = 6;
const
s можно обманом заставить быть назначенным, хотя компилятор может выдавать предупреждения:
const int FOO = 5;
(int) FOO = 6;
В зависимости от платформы назначение может по-прежнему завершаться ошибкой во время выполнения, если константа помещена в сегмент только для чтения, и это официально неопределенное поведение в соответствии со стандартом C.
Лично для целочисленных констант я всегда использую enum
s для констант других типов, я использую, const
если у меня нет очень веской причины не делать этого.
int
. Однако я был бы очень удивлен, если бы это вообще имело значение в современном компиляторе.Из кодера C:
A
const
- это просто переменная, содержимое которой нельзя изменить.#define name value
Однако, это команда препроцессора , которая заменяет все экземплярыname
сvalue
.Например, если вы
#define defTest 5
, все экземплярыdefTest
в вашем коде будут заменены на5
.источник
Важно понимать разницу между инструкциями #define и const, которые не предназначены для одного и того же.
const
const
используется для создания объекта из запрошенного типа, который после инициализации будет постоянным. Это означает, что это объект в памяти программы и может использоваться только для чтения. Объект генерируется каждый раз при запуске программы.#define
#define
используется для облегчения чтения кода и будущих модификаций. При использовании определения вы только маскируете значение за именем. Следовательно, при работе с прямоугольником вы можете определить ширину и высоту с соответствующими значениями. Тогда в коде будет легче читать, так как вместо чисел будут имена.Если позже вы решите изменить значение ширины, вам нужно будет изменить его только в определении вместо утомительного и опасного поиска / замены во всем файле. При компиляции препроцессор заменит все заданное имя значениями в коде. Следовательно, вы не теряете время, используя их.
источник
В дополнение к комментариям других людей, ошибки с использованием
#define
общеизвестно сложно отлаживать, поскольку препроцессор получает их до компилятора.источник
Поскольку директивы препроцессора не одобряются, я предлагаю использовать
const
. Вы не можете указать тип с препроцессором, потому что директива препроцессора разрешается перед компиляцией. Что ж, можно, но примерно так:#define DEFINE_INT(name,value) const int name = value;
и использовать его как
DEFINE_INT(x,42)
который будет рассматриваться компилятором как
const int x = 42;
Вы можете посмотреть мой первый фрагмент.
Обычно наличие
const
директивы вместо препроцессора помогает при отладке, но не так сильно в этом случае (но все же помогает).Оба они столь же эффективны. Я бы сказал, что макрос потенциально может быть более безопасным, поскольку его нельзя изменить во время выполнения, тогда как переменную можно.
источник
const ...
вместо макроса?pre-processor directives are frowned upon
[необходима цитата]Я использовал #define раньше, чтобы создать больше методов из одного метода, например, если у меня есть что-то вроде.
// 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;
Но мне также нужно иметь метод, который принимает только 3 числа и 2 числа, поэтому вместо написания двух новых методов я собираюсь использовать тот же самый, используя #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)
Я думаю, что это довольно круто, я знаю, что вы можете сразу перейти к методу и просто поставить nil в те места, которые вам не нужны, но если вы создаете библиотеку, это очень полезно. Также вот как
NSLocalizedString(<#key#>, <#comment#>) NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>) NSLocalizedStringFromTableInBundle(<#key#>, <#tbl#>, <#bundle#>, <#comment#>)
сделано.
Хотя я не верю, что вы можете сделать это с помощью констант. Но у констант есть преимущества перед #define, например, вы не можете указать тип с помощью #define, потому что это директива препроцессора, которая разрешается перед компиляцией, и если вы получите ошибку с помощью #define, их сложнее отладить, тогда константы. У обоих есть свои преимущества и недостатки, но я бы сказал, все зависит от программиста, которого вы решили использовать. Я написал библиотеку с ними обоими, используя #define, чтобы делать то, что я показал, и константы для объявления постоянных переменных, для которых мне нужно указать тип.
источник