Hacker News new | ask | show | jobs
by quelsolaar 606 days ago
This is one of the very rare cases in C where something is technically Undefined Behaviour, but in practice works and is recommended.

The typedef struct trick, is very common idiom that creates _more_ safety, not less. All reasonable compilers should (and do) support this. It is sad that the ISO standard is not in line with reality at all times. (I say that as a member of the wg14 and the UB study group)

I Recommend Daniel keep his typedef struct definition, and then have an ifdef to revert to the void definition for when Clang does its UB sanitizer. While checking for prototype discrepancies is a very good thing to automate, Clang should add an exception for this.

3 comments

There is no problem with using the typedef struct trick. The problem is assuming that such pointers have the same underlying representation as void pointers. Structs typically having stricter alignment requirements (whereas void* must be able to point to any byte) is one reason why their representation may differ from void*. This is why only [[un]signed] char* is guaranteed to have the same representation as void*.

Given:

    typedef struct foo Foo:
    Foo * createFoo();
    void useFoo(Foo * foo);

    Foo * foo = createFoo();
    void * vp = foo;
This is perfectly fine:

    useFoo((Foo *) vp);
This is not:

    void (*)(void *) vf = (void (*)(void *)) useFoo;
    (*fv)(vp);
Alignment only matters when you use a pointer. This is a question of if technically non compatible signatures are UB by them selves. Unaligned access is UB for sure, but even if everything is perfectly aligned they may still be UB according to the standard.

Example:

Lets say you have a function that takes a pointer to a 32 bit integer.

void my_function(int x)

But in an other file you declare it as a function taking a 32 bit float, and call it:

extern void my_function(float x); ... my_function(&my_float);

This is very likely to work in almost all implementations. float and int have the same size and same alignment requirements, but the standard may still say its UB. So it is technically UB, but may be relied upon in practice.

> I say that as a member of the wg14 and the UB study group

Since you have experience in this area, do you know how likely it is that something like this could be resolved? I.e., if someone proposed "just make this defined", how likely would the C standards body be to agree and do so?

These things can be fixed and often are. Some one just needs to write a paper proposing a change. I might in fact do so on this issue. It should be resolvable.
> very rare cases in C where something is technically Undefined Behaviour, but in practice works and is recommended.

In the bad old days, such cases were very common. I think complaining about it is a part of the process that slowly resolves it.

Lots of code has been broken because people have written UB code and then optimzers become smarter and vreak the code.

This category of we call ”usless UB” are things that wont help optimizeayions, and all major compiler have to support beacause if they dont, their users complain too much, can be relied on.

Unfortunately its very hard for the average use to know what UB can be relied on (there isnt much).