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 :)

  • 6
    Semantics (to the reader of the code): -1 is a negative number, 0xffffffff is a word (probably) with all the bits set. Without context we will have to guess. So the question is either asking for an opinion, unclear or too broad. – Richard Critten May 06 '19 at 19:56
  • 9
    x64 => -1 != 0xFFFFFFFF – Michael Chourdakis May 06 '19 at 20:03
  • 3
    Overly pedantic, probably will never run into this in the wild: C++ doesn't (yet) require 2's complement integers. -1 can have other representations. – Shawn May 06 '19 at 20:12
  • 3
    I am not sure that this represents what is considered a good C++ programming style. I had a quick look at the examples and it looks like it is more a C-oriented style of programming, using a lot of C constructs that are discouraged. If you want to learn C++, I would recommend to read https://isocpp.org/tour and https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines. – Jens May 06 '19 at 20:12
  • 2
    Since you are new to c++, you should be aware that the C++ community generally considers the use of macros to be bad practice. We prefer to use 'const unsigned int' or 'constexpr' declarations (not available in C), because these provide type information at compile time. For some reason, many OpenGL C++ tutorials tend to shy away from C++ best practices. Maybe it's because OpenGL has a C-native API. – David Dalcino May 06 '19 at 20:18
  • 1
    @MichaelChourdakis I know. Which makes this idiom even more obscure to me. – Florian Wicher May 06 '19 at 20:45
  • In two's complement, -1 will set all the bits in a number, regardless of the bit width of the container. For example, `0xff` for `int8_t` data type results in `-1`. However `0xff` for `int16_t` results in the value 255, not -1. – Thomas Matthews May 06 '19 at 20:48
  • 1
    Because `#define ERROR_VALUE -1` is buggy and the code author didn't know the right way to fix it. – Joshua May 06 '19 at 21:10
  • 1
    All that was said above is true, but if you really wanna know the code author's direction of thought, it must have been about `GLuint ` being _unsigned_, thus causing compiler warnings when being compared to negative. Despite the mentioned code problems, here it was an attempt to respect types' signedness =) – MasterAler May 07 '19 at 00:09
  • Negative 1 is only equivalent to "all bits set" in Two's complement. They're not always the same thing. – Havenard May 07 '19 at 00:20
  • @ThomasMatthews there could be padding bits, and converting `0xff` to `int8_t` is implementation-defined, not necessarily -1 – M.M May 07 '19 at 01:26
  • `0xffffffff` is not equal to `-1`. Its value is *always* `4294967295`, and its type is the first of `int`, `unsigned int`, `long int`, `unsigned long int` that can hold that value. If assigned to a 32-bit object, it *probably* has the same representation as `-1` stored in an object of a 32-bit signed integer type. Assign it to a 64-bit integer and you'll get `4294967295`. Literals specify values, not representations. – Keith Thompson May 07 '19 at 01:38

1 Answers1

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…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39