First, I found that its not possible to define the type of the constant using #define, why is that?
Why is what? It's not true:
#define MY_INT_CONSTANT ((int) 12345)
Second, are there any advantages to use one of them over the another one?
Yes. #define
defines a macro which is replaced even before compilation starts. const
merely modifies a variable so that the compiler will flag an error if you try to change it. There are contexts in which you can use a #define
but you can't use a const
(although I'm struggling to find one using the latest clang). In theory, a const
takes up space in the executable and requires a reference to memory, but in practice this is insignificant and may be optimised away by the compiler.
const
s are much more compiler and debugger friendly than #define
s. In most cases, this is the overriding point you should consider when making a decision on which one to use.
Just thought of a context in which you can use #define
but not const
. If you have a constant that you want to use in lots of .c
files, with a #define
you just stick it in a header. With a const
you have to have a definition in a C file and
// in a C file
const int MY_INT_CONST = 12345;
// in a header
extern const int MY_INT_CONST;
in a header. MY_INT_CONST
can't be used as the size of a static or global scope array in any C file except the one it is defined in.
However, for integer constants you can use an enum
. In fact that is what Apple does almost invariably. This has all the advantages of both #define
s and const
s but only works for integer constants.
// In a header
enum
{
MY_INT_CONST = 12345,
};
Finally, which way is more efficient and/or more secure?
#define
is more efficient in theory although, as I said, modern compilers probably ensure there is little difference. #define
is more secure in that it is always a compiler error to try to assign to it
#define FOO 5
// ....
FOO = 6; // Always a syntax error
const
s can be tricked into being assigned to although the compiler might issue warnings:
const int FOO = 5;
// ...
(int) FOO = 6; // Can make this compile
Depending on the platform, the assignment might still fail at run time if the constant is placed in a read only segment and it's officially undefined behaviour according to the C standard.
Personally, for integer constants, I always use enum
s for constants of other types, I use const
unless I have a very good reason not to.