Live data from Hacker News

There is no 'printf'

netmeister.org

61–70 of 158 posts

Re: There is no 'printf'

#61

Imagine somebody thought omitting the return statement and doing whatever the compiler likes is a good feature to have.

Not that odd if you know the evolution of the language... and what it actually means for modern programmers. The very first C compilers ran on a PDP-11 in just a few dozen kilobytes of memory. The entire emphasis was on minimalism, and that meant that things like type enforcement was left to the human. One of the things the earliest language was missing was the "void" type. If you didn't give a return type to a funct…

OK, but this doesn’t do wonders as a counterargument that C is just a big pile of historical baggage.

Re: There is no 'printf'

#63
In other news: man discovers compilers do things you don't expect when you operate out of spec.

Jeeze, don't tell him about semihost-supporting compilers like IAR or Keil, where printf can be one of several different things depending on your target or what configuration options are set for debugging.

Re: There is no 'printf'

#64

Quick Summary: The C compiler optimizer replaces printf("Hello World!\n") with puts("Hello World!\n") and the implicit return from main() changes from 13 (the return value of printf) to 10 (the return value of puts)

This sounds like a compiler optimizing bug, in that if the expected behavior of main without a return is that it will return the result of the last function call, then the last function in the main does use its return value and that should not be optimized.

Re: There is no 'printf'

#65

> But what if you're not using C99 or newer? If you're using C90, but under an implementation that supports C99, that implementation should obey all the new rules in all areas where there is no conflict between C90 and C99. The ISO C90 standard is obsolescent, so the fact that dropping off the end of main with no return value is an unspecified termination status is an obsolescent requirement (or non-requirement). It…

Regardless of how you think a modern compiler in C99 mode should behave, the fact is that "gcc -std=c90" generates code that returns an arbitrary value from main if no return or exit is executed.

clang doesn't do this as far as I can tell -- though it's difficult to be sure, since returning a status of 0 is valid C90 behavior.

Re: There is no 'printf'

#66

Earlier quoted context omitted.

Not that odd if you know the evolution of the language... and what it actually means for modern programmers. The very first C compilers ran on a PDP-11 in just a few dozen kilobytes of memory. The entire emphasis was on minimalism, and that meant that things like type enforcement was left to the human. One of the things the earliest language was missing was the "void" type. If you didn't give a return type to a funct…

OK, but this doesn’t do wonders as a counterargument that C is just a big pile of historical baggage.

Like the article says, this got cleaned up over 20 years ago in C99.

But sure, I wouldn't recommend anyone choose C as a language for new software unless they have an extremely good reason, or if you really love stuff like implementing every data structure you use from scratch and using void* as a kind of wildly unsafe generic.

Re: There is no 'printf'

#67

Earlier quoted context omitted.

OK, those are horrifying and fascinating, and they basically break my brain. Is there a explanation somewhere of why the first one "works"? The second one I think is the compiler assuming the default case will never be hit since it'll result in infinite recursion, which is UB under C++, so it's basically assuming 0 The first one I'm less certain about. The only thing I can think of is that the compiler deduces an upp…

My guess: since overflowing int is UB, and the only value of n that stops the recursion is zero, the compiler assumes that n must be zero and checks accordingly. That doesn’t explain why it uses test dil, 1 instead of test dil, dil or cmp 0 or whatever.

The compiler cannot assume that much, because the argument is a signed integer (negative integers will not overflow and do have well-defined behaviour).

Re: There is no 'printf'

#68
"Pop quiz! What will the following program return?

   int main() {
           printf("Hello World!\n");
   }
Easy, right? It's gotta be 0, because since at least ISO/IEC 9899:1999 (aka "C99"), main shall implicitly return 0 if you, the forgetful programmer, didn't bother to explicitly return a value:"

As hobbyist programer I write small programs and run them on older computers, running a variety of OS. Among other things, I use -std=c89 for various reasons. Thus, I know the answer to the pop quiz, for me, is not zero. Being forgetful triggers a warning.

   cat 1.c
   int main() {
           printf("Hello World!\n");
   }
   eof
   cc -Wall -std=c89 -pedantic -ansi 1.c
   ./a.out

   1.c: In function 'main':
   1.c:4:10: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
       4 |          printf("Hello World!\n");
         |          ^~~~~~
   1.c:4:10: warning: incompatible implicit declaration of built-in function 'printf'
   1.c:1:1: note: include '' or provide a declaration of 'printf'
     +++ |+#include 
       1 | 
   1.c:5:2: warning: control reaches end of non-void function [-Wreturn-type]
       5 |  }
         |  ^
As a learning exercise I try to silence the warnings one by one.

Instead of just including , which teaches me nothing, I find the prototype string and insert it the .c file using a short script something like the following

    #!/bin/sh
    test $# = 1||exec echo usage: $0 function
    grep -r " $1(" /usr/include/* 2>/dev/null|sed 's/.*://;s/ *//' 
This enables me to learn that the printf protoype uses __restrict instead of restrict, and consequently a portability note:

On Linux, __restrict is defined in /usr/include/features.h

On NetBSD, __restrict is defined in /usr/include/sys/cdefs.h

Now, with the printf() prototype included

   sed \$r1.c 2.c
   int printf(const char *restrict, ...); 
   eof
   cc -Wall -std=c89 -pedantic -ansi 2.c
   ./a.out

   2.c: In function 'main':
   2.c:5:2: warning: control reaches end of non-void function [-Wreturn-type]
       5 |  }
         |  ^
The -std=c89 option enables me to learn to use exit(). Using return statement will also suppress the warning. For the main() function however, cf. a subroutine inside main(), I use exit() instead of return.

   sed 4r2.c 3.c
           exit(0);
   eof
   cc -Wall -std=c89 -pedantic -ansi 3.c
   ./a.out

   3.c: In function 'main':
   3.c:5:35: warning: implicit declaration of function 'exit' [-Wimplicit-function-declaration]
       5 |          printf("Hello World!\n");exit(0);
         |                                   ^~~~
   3.c:5:35: warning: incompatible implicit declaration of built-in function 'exit'
   3.c:1:1: note: include '' or provide a declaration of 'exit'
     +++ |+#include 
       1 | 
Find the prototype for exit() and add it in, instead of just blindly including .

   sed 2r3.c 4.c
   void exit(int);
   eof
   cc -Wall -std=c89 -pedantic -ansi 4.c
   ./a.out

Re: There is no 'printf'

#69
post #17

So, why does puts do "return r ? EOF : '\n';"? Some backwards compatibility? Or is there a logical reason for that?

That particular implementation probably returns the result of the last fputc() or equivalent that it called. puts() returns EOF (typically -1) on error, or some unspecified non-negative value on success. fputc() returns EOF on error or the written character, treated as an unsigned char and converted to int, on success. Don't expect all puts() implementations to do the same thing. For example, the glibc implementation…

For what it's worth, musl's implementation returns 0 on success.

Re: There is no 'printf'

#70
post #24

Earlier quoted context omitted.

It's arbitrary. The article shows an implementation that returns 10 (ASCII '\n'). But the spec says it doesn't matter, so you should only be using it to test >0 for success.

The correct implementation is obviously to return 1 on success !

The correct implementation is to return any non-negative int value you like.
Post reply on HN