Hacker News new | ask | show | jobs
by p_l 756 days ago
Especially when one adds how many "low level programming" idioms for C are, as far as I understand, undefined behaviour in C. Like assigning an address to then use as pointer to physical memory...

Which is extra visible when one looks at original UNIX sources and its many short assembly bits in separate files to handle bits of direct hw manipulation.

1 comments

> Like assigning an address to then use as pointer to physical memory...

What do you mean by this? Like writing to a specific integer address?

    *((volatile unsigned *)(0x20001000)) = 0x12345678;
That's not UB and is also the only way to write to memmapped registers.
It's not UB. It's also not covered by standard - it's implementation-specified. What will happen is dependant on decision of compiler writers.

It is, however, not the only way to write to memmapped registers.

The original C way of doing so was to use an assembly function wrapping the actual act of reading/writing (honestly, better than doing the above, as it helps making it very explicit how the write will happen as well as abstracting any details like needing to add a barrier or whatsoever), the other way was to specify the symbol with address of the memmapped register in assembly, and link resulting object with C code.

A C implementation is, AFAIK, free to refuse the literal addresses used as pointers and pass as ISO C.

Both of the alternative do not generate same code though.

At least they don't without LTO.

The point of "implementation defined" is that the actual code generated is up to implementation, or in fact whether it even accepts such code.
Sure, I don't disagree.

What I mean is, most compilers won't generate a function call or an additional indirect memory access for *(111) = 222;, unlike your spec-compliant alternatives.

This is, IMO, the problem. Sometimes we just want a more ergonomic way than inline assembly in a hot loop (and also we'd like to to pretend its portable). The spec does not have an answer to this.

So, unless all C compilers in the world actively sabotage this usage (like how Go did to map traversal orders), your spec saying this is "implementation defined" have no impact at all. All C compilers are bound to implement the same intuitive but completely-not-enforced-by-spec behavior. Because if they don't, people just use something else.

> That's not UB

Please cite chapter and verse of the C standard which defines this behavior. Any edition.

I don't know if this particular example is UB or not, but the dichotomy here between 'defined' and 'not defined' is a false one, as C also specifies some constructs as having 'implementation defined' behavior. The behavior of such constructs is not defined in the standard, but is also not 'undefined' in the special sense of 'undefined behavior'.

Edit: Looks like the result in this case is implementation defined: https://stackoverflow.com/a/24212940