Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The C language provides several different kinds of constants: integer constants such as 10 and 0x1C, floating constants such as 1.0 and 6.022e+23, and character constants such as 'a' and '\x10'. C also provides string literals such as "hello, world" and "\n". These may all be referred to as literals.

Wiki Markup
UseWhen meaningfulused symbolicin constants, rather than raw valuesprogram logic, toliterals representcan arbitraryreduce constantthe values.  A well-named symbol adds clarity to the program's readability of source code. by conveying the meaning of As a constant.result, literals Usingin symbolic constants also simplifies maintenance and promotes portability by providing a single change point. Although some constants represent values that never change, many constants represent arbitrary implementation decisions, such as buffer sizes, that are subject to change. If you use a symbol to represent a constant value, you can change the value throughout the program by changing the symbol definition (the single change point) and rebuilding the program \[[Saks 02|AA. C References#Saks 02]\]. 
Avoid the use of magic numbers in code when possible. Magic numbers are constant values that represent either an arbitrary value (such as a determined appropriate buffer size) or a malleable concept (such as the age a person is considered an adult, which could change between geopolitical boundaries). Rather, use appropriately named symbolic constants to clarify the intent of the code. In addition, if a specific value needs to be changed, reassigning a symbolic constant once is more efficient and less error prone than replacing every instance of the value.
general, and integer constants in particular, are frequently referred to as _magic numbers_ because their purpose is often obscured. Magic numbers are constant values that represent either an arbitrary value (such as a determined appropriate buffer size) or a malleable concept (such as the age a person is considered an adult, which could change between geopolitical boundaries). Rather, use appropriately named symbolic constants to clarify the intent of the code. In addition, if a specific value needs to be changed, reassigning a symbolic constant once is more efficient and less error prone than replacing every instance of the value. \[[Saks 02|AA. C References#Saks 02]\]. 

The C programming language has several mechanisms for defining creating named, symbolic constants: const-qualified objects, enumeration constants, and object-like macro definitions. Each of these mechanisms has associated advantages and disadvantages.

const-qualified Objects

Objects that are const-qualified have scope and can be type-checked by the compiler. Because these are named objects (unlike macro definitions), (certain) debugging tools can show the name of the object. The objects also consumes memory (though this is not too important).

A const-qualified objects allows you to specify the exact type of the constant. For example:

Code Block

unsigned int const buffer_size = 256;

defines buffer_size as a constant whose type is unsigned int.

Unfortunately, const-qualified objects cannot be used where compile-time integer constants are required, namely to define the

...

const-qualified objects are likely to incur some runtime overhead. [Saks 01b] Most C compilers, for example, allocate memory for const-qualified objects. const-qualified objects declared inside a function body will have automatic storage duration. Consequently, if the compiler allocates storage for the object, it will be on the stack and this storage will need to be allocated an initialized each time the containing function is invoked.Also, const-qualified integers cannot be used in locations where an integer constant is required, such as the value of a case constant.

const:

  • operates at run time

Enumeration Constants

Enumeration constant can be used to represent an integer constant expression that has a value representable as an int. Unlike const-qualified objects, enumeration constants do not require that allocated storage is allocated for the value so it is not possible to take the address of an enumeration constant.

Code Block
enum { max = 15 };
int a[max]; /* OK */
const int *p;

p = &max; /* error: '&' on constant */

Enumeration constants do not allow the type of the value to be specified. An enumeration constant whose value can be represented as an int is always an int.

Object-like Macros

A preprocessing directive of the form:

...

Wiki Markup
defines an _object-like_ macro that causes each subsequent instance of the macro name to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive \[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\]. 

#define:

...

C programmers frequently define symbolic constants as object-like macros. For example, the code:

Code Block

#define buffer_size 256

defines buffer_size as a macro whose value is 256. The preprocessor substitutes macros before the compiler does any other symbol processing. Later compilation phases never see macro symbols such as buffer_size; they see only the source text after macro substitution. Consequently, many compilers do not preserve macro names among the symbols they pass on to their debuggers.

Macro names do not observe the scope rules that apply to other names. Consequently, macros might substitute in unexpected places with unanticipated results.

Object-like macros do not consume memory, and consequently, it is not possible to create a pointer to one. Macros do not provide for type checking, as they are textually replaced by the preprocessor.

Macros may be passed as compile-time arguments.

...

Summary

The following table summarizes some of the differences between const-qualified objects, enumeration constants, and object-like macro definitions.

...