const vs. #define

Oct 12, 2015 at 5:27pm
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


Oct 12, 2015 at 5:41pm
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 Oct 12, 2015 at 5:41pm
Oct 12, 2015 at 6:14pm
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?
Oct 12, 2015 at 8:07pm
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 Oct 12, 2015 at 9:50pm
Oct 12, 2015 at 9:15pm
3.14159 is a double. If you want a float you would have to write 3.14159f.
Last edited on Oct 12, 2015 at 9:16pm
Oct 12, 2015 at 10:01pm
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 ;-)
Oct 12, 2015 at 10:14pm
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.
Oct 12, 2015 at 10:35pm
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
Oct 12, 2015 at 11:40pm
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 Oct 12, 2015 at 11:50pm
Oct 13, 2015 at 12:27am
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++.
Oct 13, 2015 at 2:23am
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 Oct 13, 2015 at 2:25am
Oct 13, 2015 at 11:33pm
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 Oct 13, 2015 at 11:34pm
Oct 13, 2015 at 11:59pm
@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 )
Oct 14, 2015 at 2:21pm
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 Oct 14, 2015 at 2:23pm
Oct 14, 2015 at 2:25pm
#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.
Oct 14, 2015 at 2:34pm
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.
Oct 14, 2015 at 4:13pm
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;
}
Oct 14, 2015 at 4:14pm
Your code on line 1 is invalid.
Topic archived. No new replies allowed.