4 ms·
You're assuming that NULL represents an error. It doesn't, it represents the lack of a value. Widget w = {}; widget_init(&w); widget_debug_print(&w
by alextgordon 11y ago
You're assuming that NULL represents an error. It doesn't, it represents the lack of a value.
Widget w = {};
widget_init(&w);
widget_debug_print(&w);
void widget_debug_print(Widget* widget) {
printf("title: '%s'\n", widget->title);
printf("size: (%d, %d)\n", widget->w, widget->h);
}
I don't know what widget_init() does. It turns out that widget->title is NULL. Great! Now I know.
You're basically saying: "In an ideal world, that printf() would be enclosed in an if (), then the code is compliant".
OK, but who's going to fix it? The vendor went bankrupt years ago, the code only exits on JAZ tapes, the whole of Uzbekistan relies on it, etc...
Relevant: https://lkml.org/lkml/2012/12/23/75 https://lkml.org/lkml/2012/12/23/75
- cperciva 11y agoThe vendor went bankrupt years ago, the code only exits on JAZ tapes, the whole of Uzbekistan relies on it, etc... All the more reason why developers shouldn't be tricked into thinking that their code is correct in the first place.
- kazinator 11y agoThe code isn't incorrect, it is nonportable. If portability isn't a requirement, then it has no bearing on correctness (except that violations of other requirements that do apply to the program may also happen to be nonportable). There is such a thing as nonportable and correct. A program is correct if it implements its specification, and if the specification says "it only has to run on glibc/Linux systems" then passing null pointers to %s is irrelevant. The behavior in this case is undefined, but that only means "not defined by the ISO C standard". In context, it is the opposite to standard-defined, not the opposite to defined. In fact, the given C library has defined the behavior; for the users of that library, it is well-defined: "glibc-defined", if you will. I happen to believe that glibc's definition of behavior is arbitrary and inconsistent, but that's a whole different point from the idea that there should be no defined behavior, or that it should be defined to abort. The %s conversion specifier in glibc chooses a printed representation for the object "null pointer of type char ", the printed representation "(null)" that is not shared by other library functions. For instance, consistency says that we should see the same result if we do strcpy(big_buffer, NULL) and sprintf(big_buffer, "%s", NULL). We do not. One will crash and the other gives us "(null)". Extending behavior in inconsistent ways that breaks basic equivalences and identities is pointless. Moreover, programmers who want (char ) 0 to be "(null)" can do so easily, for instance with an inline function like this: static inline maybenull(const char *s) { returns s ? s : "(null)"; } printf("%s\n", maybenull(str)); The utility of this is low. All it does is waste cycles checking for null, which is of no benefit to a program which never passes null.