[ACCEPTED]-Advantage and disadvantages of #define vs. constants?-objective-c
As 0A0D mentioned, there are #defines
, enums
, and const
variables. It's worth 8 noting that const
-qualified variables are not 7 considered to be compile-time constants 6 in C and therefore can't be used in some 5 circumstances (e.g. when declaring the size 4 of an array).
enum
constants are compile-time 3 constants, however. For integral values, IMO 2 it's usually better to prefer enums
over const
variables 1 over #define
.
Actually there are three ways of defining 102 such constants,
defines
- enums
- const variables
In C, everything is an int 101 unless otherwise specified. I prefer enums 100 when I have a number of related integer 99 constants. Enums are clearly preferable 98 when you don't care what the values are. But 97 even when you do need to specify the values 96 for all the constants, I like the mental 95 grouping of an enum. Code documents itself 94 better when you have the type, e.g.
Error MyFunc();
clearly 93 returns one of a particular set of error 92 codes, whereas
int MyFunc()
might return one of the #define'd 91 list for Unix errno, or maybe something 90 else, or maybe those plus some idiosyncratic 89 values -- who knows? If you have more than 88 one set of return codes, which set does 87 this function use?
The more specific enum 86 type name helps the tags facility in your 85 editor, greps, debugging, and so on.
A strict 84 lint may give you some warnings about using 83 enums as integers, for example if you add 82 or or them, or pass an enum to an int.
A 81 const object is different from either an 80 enum or a #define, particularly in C. In 79 ANSI C, a const int takes up space just 78 as a regular int; most compilers will also 77 generate pointer references to this address 76 rather than inlining the value. As a result, I 75 rarely use const int's in C. (C++ has slightly 74 different semantics, and so the choices 73 are different there.)
Every compiler I've 72 ever used has the option to store enums 71 in the smallest space possible. Usually 70 it's even the default option. To force wider 69 enums when using such an option, I usually 68 throw in an extra unsigned value:
typedef enum
{
MyEnumA,
MyEnumB,
MyEnumForce16 = 7fff
} MyEnum;
The use 67 of an enumeration constant (enum) has many 66 advantages over using the traditional symbolic 65 constant style of #define. These advantages 64 include a lower maintenance requirement, improved 63 program readability, and better debugging 62 capability.
1) The first advantage is that 61 enumerated constants are generated automatically 60 by the compiler. Conversely, symbolic constants 59 must be manually assigned values by the 58 programmer.
For instance, if you had an enumerated 57 constant type for error codes that could 56 occur in your program, your enum definition 55 could look something like this:
enum Error_Code
{
OUT_OF_MEMORY,
INSUFFICIENT_DISK_SPACE,
LOGIC_ERROR,
FILE_NOT_FOUND
};
In the preceding 54 example, OUT_OF_MEMORY is automatically 53 assigned the value of 0 (zero) by the compiler 52 because it appears first in the definition. The 51 compiler then continues to automatically 50 assign numbers to the enumerated constants, making 49 INSUFFICIENT_DISK_SPACE equal to 1, LOGIC_ERROR 48 equal to 2, and FILE_NOT_FOUND equal to 47 3, so on. If you were to approach the same 46 example by using symbolic constants, your 45 code would look something like this:
#define OUT_OF_MEMORY 0
#define INSUFFICIENT_DISK_SPACE 1
#define LOGIC_ERROR 2
#define FILE_NOT_FOUND 3
Each 44 of the two methods arrives at the same result: four 43 constants assigned numeric values to represent 42 error codes. Consider the maintenance required, however, if 41 you were to add two constants to represent 40 the error codes DRIVE_NOT_READY
and CORRUPT_FILE
. Using the enumeration 39 constant method, you simply would put these 38 two constants anywhere in the enum definition. The 37 compiler would generate two unique values 36 for these constants. Using the symbolic 35 constant method, you would have to manually 34 assign two new numbers to these constants. Additionally, you 33 would want to ensure that the numbers you 32 assign to these constants are unique.
2) Another 31 advantage of using the enumeration constant 30 method is that your programs are more readable 29 and thus can be understood better by others 28 who might have to update your program later.
3) A 27 third advantage to using enumeration constants 26 is that some symbolic debuggers can print 25 the value of an enumeration constant. Conversely, most 24 symbolic debuggers cannot print the value 23 of a symbolic constant. This can be an enormous 22 help in debugging your program, because 21 if your program is stopped at a line that 20 uses an enum, you can simply inspect that 19 constant and instantly know its value. On 18 the other hand, because most debuggers cannot 17 print #define
values, you would most likely have 16 to search for that value by manually looking 15 it up in a header file.
The #define
statement is 14 a pre-compiler directive. Technically, any 13 line that begins with a # is something for 12 the pre-compiler to act on. The pre-compiler 11 will replace all instances of the defined 10 token with its definition. So doing this:
#define DELAY 40
for (i=0;i<DELAY;i++) {
for (j=0;j<DELAY;j++) {
asm NOP;
}
}
is 9 exactly the same as this (as far as the 8 compiler is concerned):
for (i=0;i<40;i++) {
for (j=0;j<40;j++) {
asm NOP;
}
}
When the compiler 7 generates machine code, it will see the 6 number 40 and use the immediate addressing 5 mode in order to compare with the accumulator. The 4 number 40 will be stored in the code as 3 many times as you are referencing it. In 2 this case it is twice. Here is the assembly 1 generated by CodeWarrior Ver5:
7: char i,j;
8: for (i=0;i<DELAY;i++) {
0002 95 [2] TSX
0003 7f [2] CLR ,X
0004 [5] L4:
9: for (j=0;j<DELAY;j++) {
0004 6f01 [3] CLR 1,X
0006 [5] L6:
10: asm NOP;
0006 9d [1] NOP
0007 6c01 [4] INC 1,X
0009 e601 [3] LDA 1,X
000b a128 [2] CMP #40 ;<---- notice opcode a1 and immediate constant 40, which is $28 in hexadecimal
000d 25f7 [3] BCS L6
000f 7c [3] INC ,X
0010 f6 [2] LDA ,X
0011 a128 [2] CMP #40 ;<---- and here it is again.
0013 25ef [3] BCS L4
11: }
12: }
13: }
Constants allow you to specify a datatype, which 7 is (usually) an advantage. Macros are much 6 more flexible, and therefore can get you 5 into much more trouble if you're not careful.
Best 4 practice is to use constants as much as 3 possible, and use #define only when you 2 really need a macro, not just a named literal 1 value.
Constants have the advantage of being typed, so 5 using them incorrectly can be discovered 4 at compile time. It may not matter to you 3 but constants take up space in memory while 2 #defines do not (since they are replaced 1 before actual compilation happens).
Constants follow type safety measures, #defines 2 are substituted outright. Also as GMan 1 said, #define's don't respect scope.
Explanation for #define:A #define is either an immediate value 19 or a macro.
Explanation for constant:A constant is a value of any 18 type which can never change.
You can delcare 17 a pointer to a const, but not to a #define, although 16 a #define could 15 be a pointer for eg: #define ADDRESS ((int 14 *)0x0012)
So why we should use constant is 13 as follows:
- they obey the language's scoping rules
- you can see them in the debugger
- you can take their address if you need to
- you can pass them by const-reference if you need to
- they don't create new "keywords" in your program.
In short, const identifiers act 12 like they're part of the language because 11 they are part of the language.
Within a module, a 10 C compiler could optimize a const as if 9 it were a #define, if there are no pointers 8 declared to the constant. In CPU terms, the 7 const would become an "immediate" value. Other 6 alternatives is that a const variable could 5 be placed in the code area as opposed 4 to the data area since it doesn't change. On 3 some machines, declaring a ponter to a constant 2 could cause an exception if you tried to 1 modify the constant via the pointer.
There are cases where #define is needed, but you should generally avoid it when you have the choice. You should evaluate whether to use const or #define based on business value: time, money, risk.
Const is an object you can take its address, for 3 example. Also it is type-safe, i.e. compiler 2 knows what the constant's type is. Above 1 does not apply to #define.
const
produces an lvalue, meaning its address can be taken.#define
doesn't.#define
can cause unintentional macro expansions, which can be a PITA to debug.- As mentioned by others,
#define
doesn't have a type associated with it.
In general, I'd avoid the preprocessor like 5 the plague for anything I didn't have to 4 use it for, mostly because of the possibility 3 of unintentional expansion and because the 2 ALL_CAPS convention for mitigating this 1 is unbelievably ugly.
1) #define's can be considered as tunable 10 parameters that are independent of the datatypes, whereas 9 constant's allow us to mention the datatype.
2) #define's 8 replaces any code that follows that in the 7 main program where ever they are referred 6 to. In addition to this we can even have 5 macro function performing a specific task, that 4 could be called by passing the parameters 3 alone. These are obviously not possible 2 in the case of constant's.
So, they are used 1 based on the relevance.
the benefit of using define is once you 5 define the variable for exp: #define NUMBER 4 30, all the code in main will use that code 3 with value 30. If you change the 30 to 40 2 it will directly change all value in main 1 which using this variable (NUMBER).
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.