How To Define An Integer Constant In C

19,881 views

Published on

A small note on const in C

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
19,881
On SlideShare
0
From Embeds
0
Number of Embeds
18
Actions
Shares
0
Downloads
22
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

How To Define An Integer Constant In C

  1. 1. How to define an integer constant in C? This is a tricky issue with a number of options available in C. They include: 3. Explicit use of literal 4. Use of preprocessor #define 5. Use of enum 6. 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: Constant Option C Preprocessor C Compiler C Debugger Integer Literal • Does not see any • Sees a Literal • No Debugger Symbol Literal or Symbol • Replaces in Expressions Entry (10) • No Memory Binding Define Constant • Sees a Symbol • Sees a Literal • No Debugger Symbol • Replaces Textually • Replaces in Expressions Entry #define TEN 10 • No Memory Binding Enum Literal • Does not see any • Sees a Symbol • Debugger Symbol with Literal or Symbol • Symbol is Constant Constant Value enum { TEN = 10 }; • Replaces in Expressions • Address Operation on • No Memory Binding Symbol an Error Created; and is Not allowed Constant Integer • Does not see any • Sees a Symbol • Debugger Symbol with Literal or Symbol • Symbol is Constant Constant Value const int TEN = 10; • Replaces in Expressions • Address Operation on • No Memory Binding Symbol an Error Created; but is allowed Constant Integer • Does not see any • Sees a Symbol • Debugger Symbol with (Address Used) Literal or Symbol • Symbol is Constant Constant Value • Replaces in Expressions • Address Operation on const int TEN = 10; for direct use; indirect Symbol allowed &TEN; use may not be replaced • Memory Binding Created in Constant Segment Next, we illustrate the above with a code below: #define u 1 // u: Symbol - No. Memory - No enum { v = 1 }; // v: Symbol - No. Memory - No; Disallowed const int w = 1; // w: Symbol - Yes. Memory - No; Allowed const int x = 1; // x: Symbol - Yes. Memory - Yes (Const Segment) const int *p = &x; // p: Symbol - Yes. Memory - Yes (Data / 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];
  2. 2. 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. #line 1 "d:personal_transparent programming_projectsdefine constantsdefine constantsmain.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: 7. Constant folding / propagation 8. The lack of optimizations and 9. 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_ProjectsDefine ConstantsDefine ConstantsMain.cxx .686P .XMM include listing.inc .model flat
  3. 3. 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_projectsdefine constantsdefine constantsmain.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 ebp mov ebp, esp sub esp, 252 ; 000000fcH push ebx push esi push edi lea edi, DWORD PTR [ebp-252] mov ecx, 63 ; 0000003fH mov eax, -858993460 ; ccccccccH rep stosd ; 14 : // LITERAL ; 15 : int a[1]; ; 16 : a[0] = 1; mov DWORD PTR _a$[ebp], 1 ; 17 : ; 18 : // DEFINE CONSTANT ; 19 : // 'u' is replaced by CPP ; 20 : // Expression '&u' is illegal in CPP ; 21 : // Symbol 'u' is undefined in Debugger ; 22 : int b[u]; ; 23 : b[0] = u; mov DWORD PTR _b$[ebp], 1 ; 24 : ; 25 : // ENUM LITERAL ; 26 : // 'v' is replaced by CPP ; 27 : // Expression '&v' is illegal in CPP ; 28 : // Symbol 'v' is defined in Debugger ; 29 : int c[v]; ; 30 : c[0] = v; mov DWORD PTR _c$[ebp], 1
  4. 4. ; 31 : ; 32 : // CONST INT ; 33 : // 'w' is replaced by CPP ; 34 : // Expression '&w' is legal in CPP ; 35 : // Symbol 'w' is defined in Debugger ; 36 : // Expression '&w' is undefined in Debugger ; 37 : int d[w]; ; 38 : d[0] = w; mov DWORD PTR _d$[ebp], 1 ; 39 : ; 40 : ; 41 : // CONST INT - ADDRESS TAKEN ; 42 : // 'x' is replaced by CPP ; 43 : // Expression '&x' is legal in CPP ; 44 : // Symbol 'x' is defined in Debugger ; 45 : // Expression '&x' is defined in Debugger ; 46 : // Reference to 'x' may not be optimized ; 47 : int e[x]; ; 48 : e[0] = *p; mov eax, DWORD PTR ?p@@3PBHB ; p mov ecx, DWORD PTR [eax] mov DWORD PTR _e$[ebp], ecx ; 49 : ; 50 : // Test(a[0], b[0], c[0], d[0], e[0]); ; 51 : ; 52 : return; ; 53 : } xor eax, eax push edx mov ecx, ebp push eax lea edx, DWORD PTR $LN9@main call @_RTC_CheckStackVars@8 pop eax pop edx pop edi pop esi pop ebx mov esp, ebp pop ebp ret 0 npad 2 $LN9@main: DD 5 DD $LN8@main $LN8@main: DD -8 ; fffffff8H DD 4 DD $LN3@main DD -20 ; ffffffecH DD 4 DD $LN4@main DD -32 ; ffffffe0H DD 4 DD $LN5@main DD -44 ; ffffffd4H DD 4 DD $LN6@main DD -56 ; ffffffc8H DD 4 DD $LN7@main $LN7@main: DB 101 ; 00000065H
  5. 5. DB 0 $LN6@main: DB 100 ; 00000064H DB 0 $LN5@main: DB 99 ; 00000063H DB 0 $LN4@main: DB 98 ; 00000062H DB 0 $LN3@main: DB 97 ; 00000061H DB 0 _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.

×