5

I've been going over and refactoring some code. I ended up changing a function from:

void setPerspective(float nearP = 0.1f, float farP = 1000.0f);

to

void setPerspective(float near = 0.1f, float far = 1000.0f);

and started getting a lot of strange 'missing ;' and 'missing )' errors.

It seems that near and far are #defined in windef.h. Fair enough; I'll avoid using them.

But then I noticed in another header file:

void setPerspective(float fov, float aspect, float near, float far);

Yet I get no trouble. Both of these header files have the same #includes...

Any idea why I'm getting issues in one, but not another? It doesn't seem to be the default parameters. Is it some arbitrary ordering of the #includes that might be causing issues with one header file and not another?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
kbirk
  • 3,906
  • 7
  • 48
  • 72

4 Answers4

7

The tokens near and far are probably defined to be null in an empty #define like this

#define near
#define far

so the pre-processor will replace them with null - they disappear prior to the compiler processing the source.

The first function declaration includes the default assignment to the parameters

void setPerspective(float nearP = 0.1f, float farP = 1000.0f);

The compiler correctly interprets nearP and farP as the parameter name and float as the type. When you change nearP to near and farP to far the pre-processor replaces them with null and you have an assignment to the float type... and the compiler throws a fit... this is what the compiler sees:

void setPerspective(float  = 0.1f, float  = 1000.0f);

In the second header file the parameters in the function prototype don't have default assignment, and the compiler sees the parameters are float and doesn't see near and far because they are null... so instead of this

void setPerspective(float fov, float aspect, float near, float far);

the compiler sees this

void setPerspective(float fov, float aspect, float , float );

which is a perfectly legal function prototype (you don't have to give the parameters names).

amdn
  • 11,314
  • 33
  • 45
  • This is what `#undef` is for ;) – slugonamission Sep 23 '12 at 23:32
  • @slugonamission - yes you are right, I've added it to my answer, thank you! – amdn Sep 24 '12 at 03:39
  • @slugonamission - after thinking about it I realized that only an empty `#define` would replace `far` and `near` with null... `#undef` tells the preprocessor that the symbol is no longer defined, so it represents itself. – amdn Sep 24 '12 at 04:04
4

At a guess, you are compiling on a Windows machine.

Once upon a long time ago, lost in the mists of time, there were machines like the Intel 8086, 80186, and 80286. On these machines, you had limited memory available. They mostly used 16-bit pointers. But then programs grew a bit, so the keywords near and far were added as qualifiers to identify different sizes of pointer.

What you're running into is a leftover from those dark primordial days. Sane computers (80386 onwards) didn't need the near and far notation, but the compilers continued to support them for backwards compatibility.

If this diagnosis is accurate, avoid using the names near and far; treat them as keywords leftover from an old version of the language.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • There is no excuse for system header files intruding into the user name space in this way; it is sloppy header file design. – Kaz Sep 23 '12 at 22:45
  • 3
    The excuse is that the decisions were made 20 or 30 years ago, before such namespace pollution rules had been enunciated, and backwards compatibility deals with the rest. I don't like it; but that's the way Microsoft has worked since forever. – Jonathan Leffler Sep 23 '12 at 22:47
  • @Kaz: It's easy to criticize, but often times there is no "right" answer. The choice was to ship a sub-optimal header, or break existing applications. They made the right choice – Ed S. Sep 23 '12 at 22:48
  • 1
    Microsoft has no clear namespace rules with regard to their headers and have broken little things here and there with every release of their SDK in the past 20 years. That there is still near and far garbage in there is just ridiculous. If someone wants to `#define` those out of the way, they can do that themselves. – Kaz Sep 23 '12 at 22:51
2

Look at this post: Near and Far pointers

They seem to have been types of pointers for accessing different types of memory but aren't used anymore.

Looks like there was a reason for them being called nearP and farP. :)

Community
  • 1
  • 1
Gung Foo
  • 13,392
  • 5
  • 31
  • 39
2

Header files are influenced not only by their own #includes but also by the #includes which occur in the root source file prior to those headers.

/* foo.cpp */
#include "bar.h"
#include "foo.h" // foo.h is influenced by whatever is brought in by bar.h

The identifiers far and near (as well as others) are extensions found in some compilers targetting the 8086/88 segmented architecture (on which ran MS-DOS and Windows 3.x). There could be something in the Windows header files for supporting legacy code, like maybe #define far (define it to nothing).

On a different note, you should usually be using double for floating point numbers. The float type is for saving storage in large arrays (it may or may not be smaller than double). On platforms that have IEEE 754 floating point numbers, float is usually a 32 bit number: it has a 7 bit exponsent and 24 bit mantissa, which is quite poor. Whereas double is a 64 bit type, with an 11 bit exponent and a 52 bit mantissa: substantially better range and precision.

Kaz
  • 55,781
  • 9
  • 100
  • 149