David Bakin’s programming blog.


`-Wzero-as-null-pointer-constant` vs `std::strong_ordering`

gcc has a warning you can enable: -Wzero-as-null-pointer-constant that seems helpful in keeping you to the modern C++ guideline to avoid 0 and NULL as “null pointer constants” - see C++ Guidelines ES.47: Use nullptr rather than 0 or NULL.

But if you try this with -Wzero-as-null-pointer-constant, then simple code such as:

auto test_3way(const int a, const int b) -> int {  
  std::strong_ordering ordering = a <=> b;  
  if (ordering == 0) return 0;  
  return ordering < 0 ? -1 : +1;  
}

gives the following errors (I also have -Werror to force all warnings to be errors, otherwise it would be a warning of course):

sample.cc:36:16: error: zero as null pointer constant [
   -Werror=zero-as-null-pointer-constant]
   36 |   if (ordering == 0) return 0;
      |                   ^
sample.cc:37:18: error: zero as null pointer constant [
   -Werror=zero-as-null-pointer-constant]
   37 |   return ordering < 0 ? -1 : +1;
      |        

Why is it talking about “null pointer constants” in this vanilla looking code?

Reason is that std::strong_ordering is defined so that you can only compare the four defined constants (less, equivalent, equal, greater) against 0, not against any other integer. This is an abstraction designed to encapsulate std::strong_ordering and make it really distinct from just the (possibly expected) 3-way comparison results -1, 0, and +1. But there’s no real way, without compiler magic, to restrict the std::strong_ordering comparison operators, at compile time, to comparing against arbitrary integers. Except for a trick, used by Microsoft (thus MinGW) which was suggested in the C++ standard1 for 3-way comparison: Use nullptr_t as the type of the second argument of the comparison, as it’s only two values are nullptr and … 0.

Also, BTW, gcc’s -municode option is broken for console programs

Using -municode which is described as

It causes the UNICODE preprocessor macro to be predefined, and chooses Unicode-capable runtime startup code.

However, it doesn’t work with -mconsole because it doesn’t understand that Unicode-enabled console programs start at wmain, and it tries to use wWinMain instead (which is for GUI programs).


  1. As seen in N4849, the C++ committee’s version of the C++ standard (2020-10-14) - search for the section “[cmp.categories]”. ↩︎