Sie sind auf Seite 1von 7

How to define an integer constant in C?

This is a tricky issue with a number of options available in C. They include:

1. 2. 3. 4.

Explicit use of literal Use of preprocessor #define Use of enum Use of constant int without or with address references

The following table shows a comparison for the above options in terms of CPP, CC and GDB:
Integer Literal (10) Define Constant #define TEN 10 Enum Literal enum { TEN = 10 }; C Preprocessor Does not see any Literal or Symbol Sees a Symbol Replaces Textually Does not see any Literal or Symbol C Compiler Sees a Literal Replaces in Expressions No Memory Binding Sees a Literal Replaces in Expressions No Memory Binding Sees a Symbol Symbol is Constant Replaces in Expressions C Debugger No Debugger Symbol Entry

No Debugger Symbol Entry

Debugger Symbol with Constant Value Address Operation on Symbol an Error

Constant Integer const int TEN = 10; Does not see any Literal or Symbol Constant Integer (Address Used) const int TEN = 10; &TEN; Does not see any Literal or Symbol

No Memory Binding Created; and is Not allowed Sees a Symbol Symbol is Constant Replaces in Expressions No Memory Binding Created; but is allowed Sees a Symbol Symbol is Constant Replaces in Expressions for direct use; indirect use may not be replaced Memory Binding Created in Constant Segment

Debugger Symbol with Constant Value Address Operation on Symbol an Error

Debugger Symbol with Constant Value Address Operation on Symbol allowed

Next, we illustrate the above with a code below: #define u 1 enum { v = 1 }; Disallowed const int w = 1; const int x = 1; Segment) const int *p = &x; Static Segment) void main() { // LITERAL int a[1]; a[0] = 1; // DEFINE CONSTANT // 'u' is replaced by CPP // Expression '&u' is illegal in CPP // Symbol 'u' is undefined in Debugger int b[u]; b[0] = u; // ENUM LITERAL // 'v' is replaced by CPP // Expression '&v' is illegal in CPP // Symbol 'v' is defined in Debugger int c[v]; c[0] = v; // CONST INT // 'w' is replaced by CPP // Expression '&w' is legal in CPP // Symbol 'w' is defined in Debugger // Expression '&w' is undefined in Debugger int d[w]; d[0] = w; // CONST INT - ADDRESS TAKEN // 'x' is replaced by CPP // Expression '&x' is legal in CPP // Symbol 'x' is defined in Debugger // Expression '&x' is defined in Debugger // Reference to 'x' may not be optimized int e[x]; e[0] = *p; return; } First let us take a look into the CPP output to understand what is actually seen by the C Compiler. The large number of blank lines is due to omitted comment lines from the source. // u: Symbol - No. // v: Symbol - No. Memory - No Memory - No;

// w: Symbol - Yes. Memory - No; Allowed // x: Symbol - Yes. Memory - Yes (Const // p: Symbol - Yes. Memory - Yes (Data /

#line 1 "d:\\personal\\_transparent programming\\_projects\\define constants\\define constants\\main.cxx" enum { v = 1 }; const int w = 1; const int x = 1; const int *p = &x;

void main() { int a[1]; a[0] = 1;

int b[1]; b[0] = 1;

int c[v]; c[0] = v;

int d[w]; d[0] = w;

int e[x]; e[0] = *p;

return;

Note that the #define symbol u has completely disappeared from the source. Next let us take a look at the Debug Assembly for the code. This tells us about: 1. Constant folding / propagation 2. The lack of optimizations and 3. Memory binding, wherever applicable. These have been highlighted ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.42 TITLE d:\Personal\_Transparent Programming\_Projects\Define Constants\Define Constants\Main.cxx .686P .XMM include listing.inc .model flat INCLUDELIB MSVCRTD INCLUDELIB OLDNAMES PUBLIC ?p@@3PBHB ; p _DATA SEGMENT ?p@@3PBHB DD FLAT:_x ; p _DATA ENDS CONST SEGMENT _x DD 01H CONST ENDS PUBLIC _main EXTRN @_RTC_CheckStackVars@8:PROC EXTRN __RTC_Shutdown:PROC EXTRN __RTC_InitBase:PROC ; COMDAT rtc$TMZ ; File d:\personal\_transparent programming\_projects\define constants\define constants\main.cxx rtc$TMZ SEGMENT __RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown rtc$TMZ ENDS ; COMDAT rtc$IMZ rtc$IMZ SEGMENT __RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase ; Function compile flags: /Odtp /RTCsu /ZI rtc$IMZ ENDS ; COMDAT _main _TEXT SEGMENT _e$ = -56 ; size = 4 _d$ = -44 ; size = 4 _c$ = -32 ; size = 4 _b$ = -20 ; size = 4 _a$ = -8 ; size = 4 _main PROC ; COMDAT ; 13 : { push mov sub ebp ebp, esp esp, 252

; 000000fcH

push ebx push esi push edi lea edi, DWORD PTR [ebp-252] mov ecx, 63 mov eax, -858993460 rep stosd ; 14 ; 15 ; 16 : : : mov ; ; ; ; ; ; ; 17 18 19 20 21 22 23 : : : : : : : mov ; ; ; ; ; ; ; 24 25 26 27 28 29 30 : : : : : : : mov ; ; ; ; ; ; ; ; 31 32 33 34 35 36 37 38 : : : : : : : : mov ; ; ; ; ; ; ; ; ; ; 39 40 41 42 43 44 45 46 47 48 : : : : : : : : : : mov // LITERAL int a[1]; a[0] = 1; DWORD PTR _a$[ebp], 1

; 0000003fH ; ccccccccH

// DEFINE CONSTANT // 'u' is replaced by CPP // Expression '&u' is illegal in CPP // Symbol 'u' is undefined in Debugger int b[u]; b[0] = u; DWORD PTR _b$[ebp], 1 // ENUM LITERAL // 'v' is replaced by CPP // Expression '&v' is illegal in CPP // Symbol 'v' is defined in Debugger int c[v]; c[0] = v; DWORD PTR _c$[ebp], 1 // CONST INT // 'w' is replaced by CPP // Expression '&w' is legal in CPP // Symbol 'w' is defined in Debugger // Expression '&w' is undefined in Debugger int d[w]; d[0] = w; DWORD PTR _d$[ebp], 1

// CONST INT - ADDRESS TAKEN // 'x' is replaced by CPP // Expression '&x' is legal in CPP // Symbol 'x' is defined in Debugger // Expression '&x' is defined in Debugger // Reference to 'x' may not be optimized int e[x]; e[0] = *p; eax, DWORD PTR ?p@@3PBHB ; p

mov mov ; ; ; ; ; 49 50 51 52 53

ecx, DWORD PTR [eax] DWORD PTR _e$[ebp], ecx

: : // Test(a[0], b[0], c[0], d[0], e[0]); : : return; : } eax, eax edx ecx, ebp eax edx, DWORD PTR $LN9@main @_RTC_CheckStackVars@8 eax edx edi esi ebx esp, ebp ebp 0 2 5 $LN8@main -8 4 $LN3@main -20 4 $LN4@main -32 4 $LN5@main -44 4 $LN6@main -56 4 $LN7@main 101 0 100 0 99 0 98 0 97 ; fffffff8H ; ffffffecH ; ffffffe0H ; ffffffd4H ; ffffffc8H

xor push mov push lea call pop pop pop pop pop mov pop ret npad $LN9@main: DD DD $LN8@main: DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD $LN7@main: DB DB $LN6@main: DB DB $LN5@main: DB DB $LN4@main: DB DB $LN3@main: DB

; 00000065H ; 00000064H ; 00000063H ; 00000062H ; 00000061H

DB _main ENDP _TEXT ENDS END

Please note that unless the address is taken the const int option has all the advantages of the other schemes and gives rise to the same code (as in other cases). In addition, it can make the constant symbol visible at the debugger. Interestingly, if a[0], b[0] etc are used somewhere, then the above codes for their initialization may also get optimized out (unless they are reassigned some other value at some other place). The same may apply to initialization via *p provided p is not reassigned in the meanwhile.

Moral: Use const int and do not take its address.

Das könnte Ihnen auch gefallen