const vs. #define

I was wondering, because of the difference between defining "const" and setting "#define". Just trying to understand how the compiler goes about.

"const" would define the type:
 
  const double pi = 3.14159;


Whereas "#define" doesn't:
 
  #define PI 3.14159 


The question is about precision/significance, and how the compiler handles this. For instance, what will be the difference between handling:
 
  #define ZERO 0 

Versus casting:
 
  const int zero = 0;

And also:
 
  const float zero = 0.000;

Which could differ from:
 
  const float zero = 0.0000;


Also i like to know how "#define" is handled by functions taking it as a variable of unknown (?) type; is this something like an overload situation?

Thank you for your help,
Peter


Macros (created with #define ) are handled by the preprocessor, not the compiler. The preprocessor is dumb and doesn't understand what C++ is, it just does find and replace as you tell it to. No type information exists at the time that this is happening.

Everywhere you use "PI" or "ZERO", the preprocessor just replaces it with "3.14159" or "0" as if you had written that originally. The compiler then sees that and has no idea that any macros were ever there to begin with.

As for your two floats, they are identical - no amount of zeroes after the decimal place will have any effect.
Last edited on
Thank you LB. Most is clear. One question remains though: does it mean that some function can take some undefined type of variable (by #define) as input; let's say a float as a character? Doesn't the function need overload possibilities?
does it mean that some function can take some undefined type of variable

No. Types are always exist in C++. There is no such thing as an undefined type.

Using LB's example, PI is replaced by the preprocessor with 3.14159. That is implicitly a float double to the compiler. Likewise, the compiler substitutes 0 for ZERO. That is implicitly an int.

Edit: Corrected float to double. Thank you Peter87.
Last edited on
3.14159 is a double. If you want a float you would have to write 3.14159f.
Last edited on
OK AbstractionAnon
Does this mean that a function calling a variable set by "#define" has to cast that variable; in a fact converting it. Or does it automatically convert. Say PI is called as a char...
I'm not looking for troubles, i want to know ;-)
Could you give an example of what you are talking about? I can't make sense of what you are saying; I speak code more easily.
Does this mean that a function calling a variable set by "#define" has to cast that variable

I think you're missing the point. As previously explained, #define is a text substitution mechanism handled by the preprocessor. Again using LB's example, when the preprocessor sees the token PI, it removes the token PI and substitutes the token 3.14159. The compiler operates just as if you had written 3.15159 instead of PI.

The compiler interprets 3.14159 as a double as explained here:
http://www.cplusplus.com/doc/tutorial/constants/
See the section labeled: Floating Point Numerals
Yes, i can not explain in right terms what is bothering me. Is in a fact c++ loosely typed?

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
#define PI 3.14159
int main ()
{
  int ros = 12 * PI;
  cout << ros << endl;
  double rox = 12 * PI;
  cout << rox << endl;
 return 0;
}


When compiled; is PI already 'integer-ed' to 3 in ros? And is PI a ready float to rox? (Both given the fact that, in this case 12, is a variable input.)

One should expect to have to cast, like:
 
 int ros = 12 * (int)PI

Last edited on
When compiled, "PI" doesn't exist - the preprocessor strips it out before the compiler ever sees it. This is what your compiler sees:
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;

int main ()
{
  int ros = 12 * 3.14159;
  cout << ros << endl;
  double rox = 12 * 3.14159;
  cout << rox << endl;
 return 0;
}
C++ is a strongly typed language. Preprocessor macros are not C++.
As added clarification:
The right-hand side of both lines,

int ros = 12 * 3.14159;

double rox = 12 * 3.14159;

both evaluate to the same value. A floating point numerical value literal is a double by default as Peter87 noted above. Before performing the multiplication the integer 12 will be promoted to a double due to C++'s implicit promotion of numerical types in performing arithmetic operations. Thus the result of the right-hand side is 37.69908 as a double. The assignment to the integer ros then yields 37 due to truncation of the decimal part and the assignment to rox yields 37.69908

Think of macro expansion this way: You have written your code in a text editor, but before sending the text file to the compiler you use your editor's search and replace function to replace PI by 3.14159 and then delete the line #define PI 3.14159 . The resulting text file is what is sent to the compiler. Consequently, the compiler has no idea what the symbol PI is so
int ros = 12 * (int)PI makes no sense.

To illustrate further the preprocessor's search and replace of define macros, suppose you had a line in the code double smallPI=3.14;

By the time the code is fed to the compiler that line will become:
double small3.14159= 3.14;

This will not compile since small3.14159 is not a legal identifier name because of the decimal point. This type of unexpected macro expansion can be insidious.

There is a notorious problem in Windows due to a Microsoft macro in windows.h called max defined as follows:

#define max(a, b) (((a) > (b)) ? (a) : (b))

This macro conflicts with the same identifier as used in the standard library. There are workarounds, but if you are not already aware of the problem it can lead to strange cryptic error messages. Prefer const variables over define macros.
Last edited on
Alrededor wrote:
To illustrate further the preprocessor's search and replace of define macros, suppose you had a line in the code double smallPI=3.14;

By the time the code is fed to the compiler that line will become:
double small3.14159= 3.14;

That's not how it works. The preprocessor is token based. It will NOT replace the letters PI contained in part of a variable name as in your example.
Last edited on
@peterbaaj yes the compiler might not be able to compile for ambigious call.
@AbstractionAnon A class (user defined type) can be undefined but declared. You might have compiler errors when forward declaring but calling a method in the header because the compiler did not read yet the cpp. (the important one that creates the obj )
ericool wrote:
@AbstractionAnon A class (user defined type) can be undefined but declared. You might have compiler errors when forward declaring but calling a method in the header because the compiler did not read yet the cpp. (the important one that creates the obj )

That's true, but what does that have to do with what I posted, or with the difference between #define and const variables?

Last edited on
#define is evil in most case , end of story..
@AbstractionAnon
No. Types are always exist in C++. There is no such thing as an undefined type

even using auto the compiler might no able to find an appropriate type , it is rare but I ve seen it.
Ericool wrote:
even using auto the compiler might no able to find an appropriate type , it is rare but I ve seen it.
I don't believe you. If the compiler cannot deduce a type for auto it will result in a compilation error. Please show an example of what you are talking about.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef Test;

struct a
{
public:
	static Test m_test;
};

int main(int argc, char* argv[])
{

	auto& test = a::m_test;
	return 0;
}
Your code on line 1 is invalid.
Topic archived. No new replies allowed.