Why use 0xffffffff instead of -1?

0

I'm coming from a Java background and make my first steps in C++ graphics programming. I worked on the ogl-dev tutorials (http://ogldev.atspace.co.uk/) and noticed that a macro with value 0xffffffff is defined. I understand that it encodes -1, but what I do not understand is why I should prefer this encoding over just writing -1. Is it for (backwards) compatibility? Does it have to do with some idiosyncracy of C? Is it an idiom?

An example:

#define ERROR_VALUE 0xffffffff

and subsequently

GLuint location = glGetUniformLocation(m_shaderProg, uniformName);
    if (location == ERROR_VALUE)
        throw new exception("error happened");

why wouldn't I write

if (location == -1)

or define my macro as

#define ERROR_VALUE -1

Thank you :)

c++
asked on Stack Overflow May 6, 2019 by Florian Wicher • edited May 6, 2019 by Florian Wicher

1 Answer

3

If you check the OpenGL specification (particularly section 7.6., page 134), you will find that glUniformLocation is actually specified to return a GLint, which is a 32-Bit signed integer type. Calling glUniformLocation is equivalent to a call to glGetProgramResourceLocation, which has a return type of GLint as well and is specified to return the value -1 upon error. The comparison of location to the 0xFFFFFFFF put there via replacement of the ERROR_VALUE macro just happens to work in the tutorial code because location is a GLuint rather than a GLint. If glUniformLocation actually returns -1 there, the -1 will first be implicitly converted to GLuint. This implicit conversion will follow modulo arithmetic and the -1 will wrap around to become 0xFFFFFFFF since GLuint is a 32-Bit unsigned integer type. If location was of signed type instead, this would not work correctly. As has been pointed out by Nicol Bolas, if you want to compare to some constant to check for success of this function, compare the result to GL_INVALID_INDEX which is there for exactly this purpose. Contrary to the macro defined in the tutorial code, GL_INVALID_INDEX is specified to be an unsigned integer of value 0xFFFFFFFF, which will cause any comparison to work out correctly because of the usual arithmetic conversions

As others have also noted in the comments above, I would not recommend that you consider the code presented in these tutorials to be representative of good C++. Using macros to define constants in particular is anything but great (see, e.g., here for more on that). We also don't normally use new to allocate an exception object to throw like here:

throw new exception("error happened");

In general, you'll want to avoid new in C++ unless you really need it (see, e.g., here for more on that). And if dynamic memory allocation is indeed what you need, then you'd use RAII (smart pointers) to take care of correctly handling the resource allocation…

answered on Stack Overflow May 7, 2019 by Michael Kenzel • edited May 7, 2019 by Michael Kenzel

User contributions licensed under CC BY-SA 3.0