#define DSP_START_ADDR 0x4000#define BUFFER_START_ADDR (DSP_START_ADDR + 0x1000)#define BUFFER_END_ADDR (DSP_START_ADDR + 0x1FFF)int get_buf_size (){ return BUFFER_END_ADDR - BUFFER_START_ADDR;}
Use of define over const
Stoffel: Although the misuse of defines can be a burden, most people seem to know how to get it right:
Oh, I know how to get it right. So did my workmate. The person who wrote the library that supplied the header file did not . And the problem was difficult to find at best--we are talking over 2 megs of source code here, where the problem had to be found by stepping through assembly.
Again, consts do not have this problem. Those who answer "oh, it''s easy enough just not to make a mistake in the first place" must forget (or have never known) what it''s like to work with other peoples'' code on massive projects.
Again, consts do not have this problem. Those who answer "oh, it''s easy enough just not to make a mistake in the first place" must forget (or have never known) what it''s like to work with other peoples'' code on massive projects.
By the way, to answer the anonymous poster(s), const variables are not always "variables that can't be modified", and "expressions involving 'const' are evaluated at runtime" isn't always true either. In fact, nearly all compilers will optimise a constant variable into inline code in a finished program.
Example 1: this is in 'debug' mode, when technically no optimisations should be done (excuse the ugly IOstreams):
Note that, although it has allocated space for X and Y (whereas #define would not), it didn't need to evaluate Z's value at runtime. Because it knows it will always be 25 (19h) at compile time, this is optimized away, even in a debug build.
Now, looking at the same code in Release build:
Note that it has done away with not only the constants X and Y, but also the variable Z, because the compiler knows their value and can just use a constant '25' to pass to the function.
The moral of this story is: don't worry about consuming space or runtime evaluation speed. 'const' is nearly always the best tool for the job in C++. The only reasons for using #define that I am aware of are header file inclusion guards, conditional compilation, and the more advanced preprocessor tricks such as Zipster mentioned.
Edited by - Kylotan on July 17, 2001 7:45:11 AM
Edited by - Kylotan on July 17, 2001 7:57:48 AM
Example 1: this is in 'debug' mode, when technically no optimisations should be done (excuse the ugly IOstreams):
58: const int X = 10;00401493 mov dword ptr [ebp-10h],0Ah59: const int Y = 15;0040149A mov dword ptr [ebp-14h],0Fh60:61: int z = X + Y;004014A1 mov dword ptr [ebp-18h],19h62:63: cout << "z:" << z;004017B8 mov eax,dword ptr [ebp-18h]004017BB push eax004017BC push offset string "z:" (00471084)004017C1 push offset std::cout (0047ee78)004017C6 call @ILT+695(std::operator<<) (004012bc)004017CB add esp,8004017CE mov ecx,eax004017D0 call @ILT+275(std::basic_ostream::operator<<) (00401118)
Note that, although it has allocated space for X and Y (whereas #define would not), it didn't need to evaluate Z's value at runtime. Because it knows it will always be 25 (19h) at compile time, this is optimized away, even in a debug build.
Now, looking at the same code in Release build:
; 58 : const int X = 10;; 59 : const int Y = 15;; 60 : ; 61 : int z = X + Y;; 62 : ; 63 : cout << "z:" << z; push 25 ; 00000019H push OFFSET FLAT:??_C@_02HHFJ@z?3?$AA@ ; `string' push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout call ??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<< add esp, 8 mov ecx, eax call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream::operator<<
Note that it has done away with not only the constants X and Y, but also the variable Z, because the compiler knows their value and can just use a constant '25' to pass to the function.
The moral of this story is: don't worry about consuming space or runtime evaluation speed. 'const' is nearly always the best tool for the job in C++. The only reasons for using #define that I am aware of are header file inclusion guards, conditional compilation, and the more advanced preprocessor tricks such as Zipster mentioned.
Edited by - Kylotan on July 17, 2001 7:45:11 AM
Edited by - Kylotan on July 17, 2001 7:57:48 AM
The stuff is of this way. Constants and defines are usually compiled at different times. Defines are done through the preprocessor . Constants are compiled by the compiler . When defines are used like constants, there is not so much difference, but the safe type one.
But defines are a lot more powerful than this. They can be used to create macros (that's like functions but where the code is as if it were inlined, and it's inlined at precompiling time), but that was already menctioned here by Zipster.
But a point about the defines that wasn't menctioned here (I think) is that they can be used for conditional compilation. That is, you can take an entire part of the code in the compiling time off the final executable just by commenting a define.
That's the way I use it:
If that code were compiled, it would compile every line, in the normal way.
But if I commented the #define BLA2 line, I would get a compiled program without the bla2(); line... And as it isn't never seen by the compiler but by the preprocessor, that part of the code could easily be anything uncompilable (a chapter of a book, for example) that it would act as if it were commented, so the compiler would never scream about that.
Conditional compiling is one of the more useful things of C, that's a really easy way to get multiple version of a same program compiled just by modifying a single line of the code.
Uh... I hope I've been clear, my text above is kinda messed
--DK
--H. Hernán Moraldo
Edited by - DoctorK on July 17, 2001 10:55:18 AM
Edited by - DoctorK on July 17, 2001 11:01:08 AM
But defines are a lot more powerful than this. They can be used to create macros (that's like functions but where the code is as if it were inlined, and it's inlined at precompiling time), but that was already menctioned here by Zipster.
But a point about the defines that wasn't menctioned here (I think) is that they can be used for conditional compilation. That is, you can take an entire part of the code in the compiling time off the final executable just by commenting a define.
That's the way I use it:
|
If that code were compiled, it would compile every line, in the normal way.
But if I commented the #define BLA2 line, I would get a compiled program without the bla2(); line... And as it isn't never seen by the compiler but by the preprocessor, that part of the code could easily be anything uncompilable (a chapter of a book, for example) that it would act as if it were commented, so the compiler would never scream about that.
Conditional compiling is one of the more useful things of C, that's a really easy way to get multiple version of a same program compiled just by modifying a single line of the code.
Uh... I hope I've been clear, my text above is kinda messed

--DK
--H. Hernán Moraldo
Edited by - DoctorK on July 17, 2001 10:55:18 AM
Edited by - DoctorK on July 17, 2001 11:01:08 AM
--DK--H. Hernán Moraldohttp://www.hhm.com.ar/Sign up to the HHM's developers' newsletter.
Please regard that the whole purpose for introducing inline functions in C++ is for the replacement of unsafe macros!!
I agree there is no way (I know about) to avoid the # macro,
but most of the defines can be eliminated by inline functions.
PS #define BLA is not a macro, but a precompiler directive, this is the main purpose for #defines
Gr,
BoRReL
I agree there is no way (I know about) to avoid the # macro,
but most of the defines can be eliminated by inline functions.
PS #define BLA is not a macro, but a precompiler directive, this is the main purpose for #defines
Gr,
BoRReL
July 17, 2001 06:20 PM
Sorry for the misinformation (I''m the Anon that posted #7 in this thread)
For the last 11 yrs, I''ve been working almost exclusively with compilers for embedded systems, and this is how the ones I used handled const. I never thought of trying it on MSVC before posting (didn''t have access to it at the time).
In our systems, the ''const'' is used a lot of times to either:
1. Specify that the data will go into ROM or,
2. Provide some protection so that someone can''t inadvertently change a location
The #2 a lot of times can be used for EEPROM locations. You can''t accidentally change them in the code without some specific manipulation (it won''t compile), but their values may change externally, which may be why the compiler doesn''t fold the constants in an equation at compile time.
I don''t know enough about console and handheld development to know if there are some similarities to the types of embedded systems I''ve worked on (HVAC & process control industry), so my previous post might have only caused confusion.
For the last 11 yrs, I''ve been working almost exclusively with compilers for embedded systems, and this is how the ones I used handled const. I never thought of trying it on MSVC before posting (didn''t have access to it at the time).
In our systems, the ''const'' is used a lot of times to either:
1. Specify that the data will go into ROM or,
2. Provide some protection so that someone can''t inadvertently change a location
The #2 a lot of times can be used for EEPROM locations. You can''t accidentally change them in the code without some specific manipulation (it won''t compile), but their values may change externally, which may be why the compiler doesn''t fold the constants in an equation at compile time.
I don''t know enough about console and handheld development to know if there are some similarities to the types of embedded systems I''ve worked on (HVAC & process control industry), so my previous post might have only caused confusion.
quote:
Original post by Anonymous Poster
Sorry for the misinformation (I''m the Anon that posted #7 in this thread)
For the last 11 yrs, I''ve been working almost exclusively with compilers for embedded systems, and this is how the ones I used handled const. I never thought of trying it on MSVC before posting (didn''t have access to it at the time).
Well, how a compiler treats constants is obviously compiler-dependent. Generally, a compiler is allowed to do whatever it wants with your code, providing the logic remains the same. So what you said wasn''t wrong, just not always the case, and not the case on MSVC.
quote:
In our systems, the ''const'' is used a lot of times to either:
1. Specify that the data will go into ROM or,
2. Provide some protection so that someone can''t inadvertently change a location
Yeah. When you think about it, it makes a lot of sense. On a desktop PC, memory is cheap, so compilers are likely to sacrifice size to gain speed, by substituting out the constants. Whereas on an embedded platform, where small code size may be important, and where there may be special provision for read-only memory, it makes sense to make use of such ROM to store constants.
quote:
The #2 a lot of times can be used for EEPROM locations. You can''t accidentally change them in the code without some specific manipulation (it won''t compile), but their values may change externally, which may be why the compiler doesn''t fold the constants in an equation at compile time.
Incidentally, if the value might change externally, it should have the ''volatile'' qualifier, which is precisely what it''s there for. A compiler should generally feel free to optimise away ''const'' variables as they are only modifiable within your program. (Although it probably still wouldn''t do so on your platform due to code size considerations.) However a ''const volatile'' variable is specified as one where your program won''t change it, but that could be changed externally. In this case, the compiler will not optimize it out, and additionally will be sure to read it each time before using its value.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement