Hacker News new | ask | show | jobs
by leni536 29 days ago
Undefined means that the ISO C doesn't define the behavior. An implementation is free to do so.
1 comments

If they do, that is no longer an implementation of C. It is a dialect of C, and there are many (GNU C being the most popular), but there are real drawbacks to using dialects.

This is in contrast to the other category that exists, which is "implementation-defined".

The thing is that the actual compiler behaviour matters more for real-world projects than what the C standard says. E.g. the C standard was always retroactive, it merely tried to reign in wildly different compiler behaviour at the time when the standard was new. It mostly succeeded, but still the most useful C and C++ compiler features are living in non-standard extensions.
Unaligned access being fine in one architecture, but not in others would create separate dialects, regardless of being blessed by ISO C.

Just don't do unaligned access, it's a dialect that doesn't exist currently, and should never exist.

> Unaligned access being fine in one architecture, but not in others would create separate dialects, regardless of being blessed by ISO C.

That doesn't mean unaligned access would need to be UB. It could be implementation defined. Or could just be defined to result in an error on all machines.

Implementation-defined without further constraining the behavior is not much better than undefined.

Defining it to always error would add overhead even for proper aligned access on x86, as the generated code would need to explicitly check in many cases.

> Implementation-defined without further constraining the behavior is not much better than undefined.

No, it's a lot better. Because implementations have to define it.

> If they do, that is no longer an implementation of C.

This is plain wrong. Undefined behaviour, means the C standard specifies no restriction on the behaviour of the program, which is what the implementation chooses to emit. An implementation can very well choose to emit any program it pleases, including programs that encrypt your harddisk, but also programs that stick to well defined rules.

Sure, but the point is that code written against such a compiler is not C and is not portable. It is written in a dialect of C, and that comes with drawbacks.

Writing C (or any language) means adhering to the standard, because that's the definition of the language.

Maybe it’s a generation thing. Languages like ML and Lisp have many implementations, while newer languages like Perl and Python are steered by a single organization. It’s way easier for the latter to have a single source of truth.

The C standard reminds me of Posix. You have a rough guideline if you ever wanted to port a program, but you actually have to learn the new compiler and its actual behavior before doing so.

C started off as a single implementation, then a bunch of implementations, and only later the standard.

There's multiple implementations of Python, but you are right that CPython is the big one. Part of that dynamic is that CPython runs on nearly everything well enough (well, as good as Python runs), so that we don't really need multiple implementations. Unlike the first C Compilers.

Of course, Lisp is a family of languages these days. Scheme and Common Lisp have many implementations, but Racket or Arc only have one.

You can't make any useful software in "Portable C" - or any portable language for that matter.

Side effects matter, and they are always non-portable/implementation defined/dependent on the hardware.

What printf() actaully does is implementation defined - what does "printing mean", does a console even exist? Maybe a user expects it to show graphical ascii/utf8 glyphs on a LCD display? Well, not every computer has that, so now what?

> You can't make any useful software in "Portable C" - or any portable language for that matter.

Have you heard of Java or even Python or JavaScript?

> Side effects matter, and they are always non-portable/implementation defined/dependent on the hardware.

Granted. But how does the need for implementation defined excuse undefined behaviour?

> What printf() actaully does is implementation defined [...]

> Well, not every computer has that, so now what?

The standard can be written conditionally: 'if the computer has display, printf shall show something.'

I agree, that most practical programs will rely on unportable behaviour, but

> What printf() actaully does is implementation defined - what does "printing mean", does a console even exist? Maybe a user expects it to show graphical ascii/utf8 glyphs on a LCD display? Well, not every computer has that, so now what?

You can very well write a program, that doesn't make an assumption about any of those things. In fact you should, because the user is to be the arbiter of in what environment your program gets invoked and what it gets connected to. Writing a program that makes assumptions about the specific behaviour of stdout is going to be highly impractical and annoying and also violates the abstraction and interface that stdout is. This consideration isn't just valid for stdout, but also for any other interface your programs naturally interfaces with.

> Well, not every computer has that, so now what?

In the case stdout is not available or can't process your data it is going to return -1 and set errno and then you can deal with that.