Remix.run Logo
gignico 3 hours ago

> It seems that some people are really losing the taste for good readable code.

It seems that some people never had taste for good reliable code. Use `void ` and now any error whatsoever is a direct undefined behavior. Moreover `std::span` clearly says that you are not* taking ownership of the memory (even though the language does not check it of course), while `void *` does not.

I understand that people can have many things to say about C++, and I do as well, but `std::span` should have been there decades ago and is such a life saver in these situations. A truly zero-cost abstraction which effectively saves you from a lot of troubles.

trumpdong 3 hours ago | parent | next [-]

There's lots of UB in C-family execution models. Some of which is not actually UB because the implementation defines it - e.g. aligned DWORD-sized memory access is atomic on Windows because Microsoft said it is.

By choosing to use this language you choose to navigate the UB. Otherwise you'd be writing in Go, or Python.

It is possible to write reliable code despite the presence of UB in a language just like it's possible to drive to work every day for 20 years despite most of the directions you can point the car leading to an immediate crash. That's a needle with a much thinner eye than UB in C, and most people manage it. Mainly it means being very careful about lifetime and ownership. The Linux kernel manages it 99% of the time simply by being careful about lifetime and ownership, and that's a project with a huge number of contributors who don't intimately know each other's modules. I'm the Linux kernel you can't just say "new whatever" - you must have a plan for a lifetime of that whatever, and other people will review it.

I agree with you about std::span.

pjc50 an hour ago | parent | next [-]

> Some of which is not actually UB because the implementation defines it

No - if something is UB in the spec, it's UB. The implementation will do something, sure, but what it does is not fixed and may even change based on compiler version and optimization level.

> DWORD-sized memory access is atomic on Windows because Microsoft said it is

Well, Intel said it is. Mind you I don't think there are any 32-bit native architectures where aligned dword access isn't atomic. Unaligned, on the other hand ...

trumpdong 22 minutes ago | parent | next [-]

"Undefined behavior" in the C standard literally means "behavior which this C standard does not put any requirements on" - it says so in the definitions section of the C standard. Other things can still put requirements on it. MSVC isn't just a C++ compiler - it's a C++ compiler for x64 Windows and therefore follows the rules of C++, x64, and Windows all at once.

simiones an hour ago | parent | prev [-]

> No - if something is UB in the spec, it's UB.

A compiler is still free to ignore the spec and declare that something is not UB. However, this is very much compiler based, not platform based. Windows might guarantee that aligned DWORD-sized memory accesses are atomic, but that doesn't mean Clang when compiling for Windows would respect this - but MSVC might.

arcticbull 2 hours ago | parent | prev | next [-]

Yeah but also, quick question:

  struct S {
      char c;
      int i;
  };

  struct S a = {0};
  struct S b = {0};

  memcmp(&a, &b, sizeof(a)) == ...
If you answered 0, you'd be wrong, the answer is undefined, thanks to padding, initialization and alignment rules. Padding bytes are undefined, and not guaranteed to be initialized to zero even if the variable is declared static (where the members would be zeroed).

This is why the compiler is angry at the post writer, and why the reinterpret_cast is needed. Ideally if they wanted to do something with the data, they'd unbox the structure.

That's why it's not a good idea to use void* to pass arbitrary data interchangeable with bytes. It's a location, it makes no representation as to what's there and how to interact with it. Let alone who owns it.

std::span solves two problems here. One is the ownership problem. The other is that span<T> is a T[]. void* is god only knows.

The post asserts:

> The code is very clear and straightforward: you pass a pointer to the custom data structure, and its size in bytes. That’s it. Simple and clear.

This is unfortunately entirely false in C thanks to the aforementioned alignment/padding UB (and of course inner pointers). This is addressed with std::span. You'd still have to reinterpret_cast your structure to get the UB.

> Why should people complexify and uglify their C++ code with the uint8_t pointer (or std::byte), when void* works just fine??

tl;dr: because it doesn't. It just kinda looks like it does if you squint, and it's going to lead to the gnarliest bugs in the world.

saagarjha 39 minutes ago | parent | next [-]

Padding bytes are initialized to zero if you zero initialize the aggregate. It is hard to keep those bytes as zero but at initialization this much is guaranteed.

porridgeraisin an hour ago | parent | prev [-]

> even if the variable is declared static

No, for static even padding bytes are zero.

For automatic, yes it may effectively turn a = {} to a.member = 0, leaving the padding bytes uninitialised. Or on copies like a = b it may not copy padding bytes.

repelsteeltje 2 hours ago | parent | prev [-]

There is a difference between UB in C, and something being undefined in some version of Microsoft C on Windows.

Many of C's UB is specifically, intentionally left undefined in the standard to express code that relies on some specific way it is handled, is not proper, portable C. Indeed, the DWORD-sized memory access being atomic doesn't apply to MS Windows prior to version 3.0 running on a 80286.

It's UB because the ISO C spec says it's UB.

delta_p_delta_x 2 hours ago | parent | prev | next [-]

> A truly zero-cost abstraction

Sadly the MSVC ABI makes std::span and std::string_view a pessimisation:

https://github.com/tringi/win64_abi_call_overhead_benchmark

https://godbolt.org/z/7baaox7re

usrnm an hour ago | parent [-]

Sounds like a compiler bug to me. It is a valid reason to avoid them in some rare cases right now, but it doesn't make the feature itself bad

j16sdiz an hour ago | parent [-]

Those are ABI. Unless it is inlining them, the overhead is to stay.

usrnm 2 minutes ago | parent [-]

ABI changes do happen. gcc had an ABI change in std::string because of C++11. It was long and painful, but everyone survived, the world did not end

spacechild1 3 hours ago | parent | prev | next [-]

> but `std::span` should have been there decades ago

Absolutely! I now use it consistently in all new projects where I can afford to mandate C++20. I guess nobody bothered to make a proposal before...

pjmlp 2 hours ago | parent [-]

They did in C, from one of the language authors even, and it was not accepted.

https://www.nokia.com/bell-labs/about/dennis-m-ritchie/varar...

By the way, both Extended Pascal, Mesa/Cedar and Modula-2 have them, under the name of open arrays.

Basically it took Go, C# and others for C++ to finally get its span.

C probably never will.

spacechild1 16 minutes ago | parent [-]

Everybody knows that C++ did not invent the concept of spans and that it was late to the party. It doesn’t change the fact that (presumably) nobody made a proposal to the C++ standard.

pjmlp 2 hours ago | parent | prev | next [-]

That is quite common among C developer culture, play loose and brace for impact.

locknitpicker 2 hours ago | parent | prev [-]

> I understand that people can have many things to say about C++, and I do as well, but `std::span` should have been there decades ago (...)

Decades is kind of a stretch. C++11 introduced smart pointers, and finally getting C++0x out of the door was already a major victory. Given the history of C++, it would be unrealistic to introduce something like std::span before C++17.

Meantime, some organizations are still struggling to migrate to something like C++14.

pjmlp 2 hours ago | parent | next [-]

It could have been there since the beginning, given that open arrays (aka spans) already existed in other languages, and there was even a failed proposal from Denis Ritchie regarding C.

The C++ span proposal came from Microsoft,

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p01...

gignico 25 minutes ago | parent | prev [-]

Afaik std::span does not need anything that was not in C++98 already, or am I missing something?

locknitpicker 6 minutes ago | parent [-]

> Afaik std::span does not need anything that was not in C++98 already, or am I missing something?

You're missing the fact that following C++98 it took around 13 years to get the next version of the standard published delivered.