Live data from Hacker News

Three new utility functions in C++23

mariusbancila.ro

151–160 of 196 posts

Re: Three new utility functions in C++23

#151
post #6

Hmm. How often do people actaully want to std::byteswap as opposed to "convert this value from native byte order to big-endian" or "convert this value from little-endian to native byte order"? i.e., the functions documented in https://man7.org/linux/man-pages/man3/endian.3.html (why oh why are they not also documented in the GNU C Library Manual...)

I've always thought that it should have been possible in C and C++ to declare endian-ness as the property of a member variable's type, and that's it: the compiler would then automatically choose where to swap the byte-order to/from he native byte order.

The benefits are obvious: Code is declarative, and there's no risk of a bug where you missed to call std::byteswap() or did it twice.

Also, the compiler could automatically extract and insert values from/to little-endian and big-endian bitfields (which can be a handful...), and it could optimise to reduce the number of byteswaps in the code.

Re: Three new utility functions in C++23

#152

Earlier quoted context omitted.

The point is that you're telling the compiler "I don't care what happens if control reaches here. Assume it never will and use that information to better optimize the rest". It's not an alternative to abort() or throwing because the compiler still needs to generate code for them.

Yes, that’s what I mean, the compiler can completely remove a branch which is unreachable, along with any checks. If it was forced to keep the checks and report an error instead, any bug would be more obvious. If the compiler removes checks for bugs, then the application could silently continue, obscuring the bug. So this is a “hide bugs but maybe improve performance” function.

No, it doesn't hide bugs. It has no defined effect on the obviousness of bugs. The reason is that modern compilers are pretty much theorem solvers, and they're able to propagate truth values in order to deduce facts about programs. For example, a compiler could deduce that since a branch is never reached, a particular pointer is never null, and could therefore skip a null check that it deduced was redundant that would have prevented a null dereference. If it turns out that the branch is reachable and the pointer is null, the pointer would be dereferenced and the program would crash immediately (typically). But UB is UB; once you hit it all behaviors are permissible, from immediate crash, to silent data corruption, to nasal demons.

Re: Three new utility functions in C++23

#153
post #47

Earlier quoted context omitted.

1. It is a compiler defined function (`__builtin_unreachable()`), but the issue is that MSVC doesn't have it, so you need a different implementation per compiler [0]. Plus, if a new compiler shows up (besides MSVC/GCC/LLVM), you'd need to investigate what the correct way to express `__builtin_unreachable` is. From a compiler perspective, using a function makes the most sense, since that fits into the existing control…

> Technically, this isn't the case in C either: the type defaults to `int`, but the compiler will pick a larger type if necessary, e.g. `enum Z { a = ((long long)INT_MAX) + 1 };` if you read this and alarm bells didn't ring in your head I really invite you to immediately go check any enum you may have defined in your code because this is absolutely false with MSVC in C++ ( https://gcc.godbolt.org/z/6bqW9rE81 ) (and C…

In practice I don't think that the latitude of making enum size depend on the enumeration has ever been used as it would be too easy to break the ABI. IIRC compilers have allowed forward declaring enums as an extension before c++11 which obviously doesn't work if the size depends on the definition.

Re: Three new utility functions in C++23

#154
post #111

Earlier quoted context omitted.

>Pragmas are processed by the pre-processor This is wrong a lot of pragmas, I would even say most pragmas are not handled by preprocessor. Some examples: pragma pack, warning control, pragma GCC unroll, per function optimization setting changes, all the pragmas which 1:1 map to c++11 style attributes. None of that is handled by preprocessor, pragma once seems like rare one which is. Yes all of them are compiler speci…

I meant that they are processed before any syntactical analysis, so they're not particularly useful for this kind of thing. For example, these are all wrong usages of our hypothetical `#pragma unreachable`: void foo(); #pragma unreachable class bar { #pragma unreachable }; namespace foobar { #pragma unreachable } But pragmas can generally be used anywhere, barring tokenization issues. The end result is that `pragma u…

If pragma works for omp for it would work for unreachable. But it is just ugly and there really wouldn't be any reason to use it here.

Re: Three new utility functions in C++23

#155
post #137

Earlier quoted context omitted.

Not if you look at the result.

What do you mean? Sorting is done by swapping elements ( swap(a[i], a[j]) )

Well, first, whether swap() is used or not depends on the algorithm; second, the result of the sorting, as opposed to reversal, does not necessary look like the elements were swapped.

Re: Three new utility functions in C++23

#156

Earlier quoted context omitted.

Is there syntax available in C++ to write some kind of instruction to the compiler which is not some kind of call? Even __builtin_trap is a call isn't it? What else could you attach a directive to?

c++11 style attribute. There are already similar attributes [[unlikely]] and [[likely]] which can be attached to any statement. Having [[unreachable]] wouldn't be that surprising. C++23 also introduced [[assume(expr)]] which is basically conditional unreachable. I don't see a reason why standard committee couldn't have defined that [[assume(false)]] can be used for that purpose instead of new builtin. Either of the t…

[[assume(expr)]] has a lot of controversy about what you can do with it. I haven't read the latest papers (I really should), but there is a good argument to be made that the expression means flag an error if this happens, but otherwise keep running. There are embedded systems where they have to keep running no matter what. They want to use [[assume]] as a hint to program provers about what shouldn't happen, but they still want the compiler to generate the error handling code for that condition. Unreachable by contrast means don't generate code and nobody will argue otherwise.

Again, I'm not up on the latest papers, but that was the situation last I checked.

Re: Three new utility functions in C++23

#157

Earlier quoted context omitted.

It seems like optimization cases where this makes sense are generally of the sort where `noreturn` can't be used because it is conditional. That makes sense to me (although, could this have covered most use cases by making `noreturn` support being passed the name of a function argument?). One example was interesting, though. I could see someone believing these might produce the same optimized assembly (-O2): void a(i…

Technically these would still produce different results if y started two bytes after x -- I can't remember if that is itself legal however!

No that wouldn't be legal. Distinct objects can't partially overlap, unless one is a subject of the other.

Re: Three new utility functions in C++23

#158

Earlier quoted context omitted.

Right elsethread I said that it is both about optimizations and static analysis. That's a static analysis case.

It seems like optimization cases where this makes sense are generally of the sort where `noreturn` can't be used because it is conditional. That makes sense to me (although, could this have covered most use cases by making `noreturn` support being passed the name of a function argument?). One example was interesting, though. I could see someone believing these might produce the same optimized assembly (-O2): void a(i…

Attempting to emulate restricted with __builtin_unreachable has been one of the first thing I tried when I learned about unreachable. I periodically try again, but generally I have been underwhelmed with trying to give gcc value range informations with it.

Re: Three new utility functions in C++23

#159
post #124
post #71

Earlier quoted context omitted.

In a real codebase, this would be wrapped by a macro to abort in a debug build but gain the optimizations in a release build.

cppreference suggests this as an implementation for std::unreachable but as near as I can tell neither clang nor MSVC does that (yet?).

I would have expected the _LIBCXX_ASSERTIONS macro in libc++ to affect the behavior, similarly to many other standard library undefined behaviors.

Re: Three new utility functions in C++23

#160
post #150

Kind of off topic, but is there a good "catch up" guide for people who stopped paying attention after C++11? Like a quick summary of just the useful, practical things you'd actually want to use in production, rather than the parts that are only interesting to computer science academics? Most of the "what's new in C++X" guides seem to just dump everything on you at once. I feel like I should get back into C++ but I do…

Herb Sutter’s Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14

Effective modern C++ is by Scott Meyers, not Herb Sutter.
Post reply on HN