TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

There is no 'printf'

325 点作者 pr0zac超过 3 年前

21 条评论

monocasa超过 3 年前
There is &#x27;printf&#x27;. It&#x27;s just that printf (and the rest of the standard library) is technically as much a part of the C language as the language grammar itself, and C compilers are welcome to use innate knowledge of those functions for optimizations. The other place you typically see this is calls to functions like memcpy&#x2F;memset being elided to inline vector ops or CISC copies, or on simpler systems, large manual zeroing and copying being elided the other way to a memset or memcpy call.<p>C compilers will typically have an escape hatch for envs like deeply embedded systems and kernels like gcc&#x27;s -ffreestanding and -fno-builtin that says &quot;but for real though, don&#x27;t assume std lib functions exist or you know what they are based on the function&#x27;s name&quot;.<p>&lt;rust_task_force&gt; One of my favorite parts of rust as someone who uses it for deeply embedded systems is the separation of core and std (where core is the subset of std that only requires memcpy, memset, and one other I&#x27;m forgetting). The rest of the standard library is ultimately an optional part of the language with compiler optimizations focused on general benefits rather than knowing at the complier how something like printf works. no_std is such a nicer env than the half done ports of newlib or pdclib that everyone uses in C embedded land. &lt;&#x2F;rust_task_force&gt;
评论 #28953506 未加载
评论 #28963229 未加载
评论 #28951912 未加载
rrauenza超过 3 年前
Quick Summary:<p>The C compiler optimizer replaces printf(&quot;Hello World!\n&quot;) with puts(&quot;Hello World!\n&quot;) and the implicit return from main() changes from 13 (the return value of printf) to 10 (the return value of puts)
评论 #28951566 未加载
评论 #28952691 未加载
评论 #28952363 未加载
tptacek超过 3 年前
Huh, this is pretty great; I&#x27;ve always fussily used fputs() when I&#x27;m just printing static strings, and apparently I don&#x27;t need to bother, since the compiler will just do it for me.
评论 #28957200 未加载
eikenberry超过 3 年前
<a href="https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20211019052752&#x2F;https:&#x2F;&#x2F;www.netmeister.org&#x2F;blog&#x2F;return-printf.html" rel="nofollow">https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20211019052752&#x2F;https:&#x2F;&#x2F;www.netme...</a>
RcouF1uZ4gsC超过 3 年前
This is a bit like saying there is no &#x27;+&#x27;;<p>Because if you put in<p><pre><code> return 1+2+3; </code></pre> And look at the assembly code, you will see that the compiler generated something like<p><pre><code> return 6; </code></pre> The compiler is allowed to take advantage of the standard to substitute in more efficient code that does the same thing.<p>IIRC, for C++, it would actually be ok if std::vector was implemented completely as a compiler intrinsic with no actual header file. (No compiler I am aware of actually does it that way).
评论 #28950762 未加载
评论 #28950640 未加载
评论 #28951368 未加载
评论 #28950665 未加载
kazinator超过 3 年前
&gt; <i>But what if you&#x27;re not using C99 or newer?</i><p>If you&#x27;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.<p>The ISO C90 standard is obsolescent, so the fact that dropping off the end of <i>main</i> with no return value is an unspecified termination status is an obsolescent requirement (or non-requirement).<p>It is possible for a conforming C90 implementation to return 0 in that case. A conforming C99 implementation <i>must</i> do that as a conformance requirement. There is no good reason for a C99 implementation behaving in a C90 compatibility mode to simply drop non-conflicting C99 requirements and revert a behavior such as this.<p>This should be a don&#x27;t care issue, unless you&#x27;re targeting a <i>bona fide</i> nothing-but-C90 implementation.<p>However, if you are telling your implementation to be C90, what reason are you doing that for? If it&#x27;s not just some nerd gesture to show your contempt for C99, and you really care about portability to C90 implementations, then you probably want to be returning an explicit 0 from your main. Or even just to show contempt for C99, really, you should be returning that 0.
评论 #28952698 未加载
评论 #28952969 未加载
评论 #28955113 未加载
jeroenhd超过 3 年前
My compilers call printf just fine until you enable optimizations. -O0 adds references to printf, -O1 and higher switches to puts.<p>I was kind of surprised about the fact that there was no warning about the missing return from main(). Normally, I&#x27;d expect the compiler to complain that a supposed int returning function does not return anything, because that would normally be undefined behaviour.
评论 #28952009 未加载
评论 #28952036 未加载
kazinator超过 3 年前
There is no <i>printf</i> because there is no defined behavior.<p>To call a variadic function, you must have a prototype declaration in scope. (A correct prototype, needless to say.)<p>A non-prototype (i.e. old-style) declaration cannot declare a variadic function such as <i>printf</i>, so no such declaration can be correct.<p>If the function is not declared, then a declaration will effectively be assumed for the call, deduced from the types of the actual arguments, and a return value of <i>int</i>. In this case, the function will be &quot;implicitly declared&quot; to look something like<p><pre><code> int printf(char *); </code></pre> but that is not the correct declaration for <i>printf</i>. Therefore, the call has undefined behavior.<p>The optimizer is allowed to rewrite this to:<p><pre><code> puts(&quot;daemons are running in your nose&quot;); </code></pre> Likewise, it is allowed to rewrite it to:<p><pre><code> puts(&quot;Hello World!&quot;);</code></pre>
评论 #28952465 未加载
guerrilla超过 3 年前
Moar please. I&#x27;m loving these counterintuitive C optimization gotchas lately[1]. They are like little brain teasers.<p>1. <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=28930271" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=28930271</a>
评论 #28950831 未加载
评论 #28950880 未加载
mormegil超过 3 年前
So, why does puts do &quot;return r ? EOF : &#x27;\n&#x27;;&quot;? Some backwards compatibility? Or is there a logical reason for that?
评论 #28951011 未加载
评论 #28950842 未加载
评论 #28950735 未加载
anonymousiam超过 3 年前
Compiler optimization can sometimes cause unpredictable or even incorrect behavior. Below is a blob of C code for the TI MSP430 compiler that exemplifies at least one of TI&#x27;s optimization bugs:<p>&#x2F;&#x2F; Define Common Communications Frame<p>typedef volatile union commFrameType<p>{<p><pre><code> struct { unsigned SyncHeader:16; unsigned MessageID:8; unsigned short MessageData[msgDataSize]; &#x2F;&#x2F; ID-unique data unsigned CRC:8; &#x2F;&#x2F; LSB of CCITT-16 for above data } __attribute__ ((packed)) Frame; unsigned char b[16]; &#x2F;&#x2F; Accessible as raw bytes as well unsigned short w[8]; &#x2F;&#x2F; Accessible as raw words as well unsigned long l[4]; &#x2F;&#x2F; Accessible as raw long words as well </code></pre> } __attribute__ ((packed)) CommFrame;<p>static CommFrame IpcMessage = { FRAME_SYNC_R, IpcBlankMessage };<p><pre><code> &#x2F;&#x2F; If frame was accepted into TX queue, prepare next frame for transmission </code></pre> &#x2F;&#x2F; IpcMessage.Frame.MessageID++; &#x2F;&#x2F; Bump up to next message type<p>&#x2F;&#x2F; IpcMessage.Frame.MessageID += 1;<p>&#x2F;&#x2F; The above two lines that are commented out cause a bizzare linker error if either are used instead of the line below.<p><pre><code> IpcMessage.Frame.MessageID = IpcMessage.Frame.MessageID + 1; &#x2F;&#x2F; Bump up to next message type </code></pre> The MSP-430 is a 16-bit microcontroller and the packed CommFrame structure has Frame.MessageID on an odd-byte boundary. Some processors might raise a SIGBUS, but TI says that it&#x27;s okay to access a byte on an odd address boundary.<p>It&#x27;s pretty silly that i++; and i+=1; don&#x27;t work, but i=i+1; is just fine.
评论 #28951136 未加载
GoblinSlayer超过 3 年前
Imagine somebody thought omitting the return statement and doing whatever the compiler likes is a good feature to have.
评论 #28952512 未加载
评论 #28955890 未加载
评论 #28951214 未加载
cyberge99超过 3 年前
Apparently there is no available capacity for that site either.
评论 #28950662 未加载
ltr_超过 3 年前
[off topic] I always wondered how &#x27;%n&#x27; is used in production code.
评论 #28951885 未加载
DeathArrow超过 3 年前
When you call printf you will actually issue a system call to write to stdout. Does stdlib directly issue system calls or does it use some inline assembly?
评论 #28954583 未加载
qwerty456127超过 3 年前
&gt; puts(3) only returns &quot;a nonnegative integer on success and EOF on error&quot;<p>How does it decide which nonnegative integer to return?
评论 #28950941 未加载
评论 #28950920 未加载
1vuio0pswjnm7超过 3 年前
&quot;Pop quiz! What will the following program return?<p><pre><code> int main() { printf(&quot;Hello World!\n&quot;); } </code></pre> Easy, right? It&#x27;s gotta be 0, because since at least ISO&#x2F;IEC 9899:1999 (aka &quot;C99&quot;), main shall implicitly return 0 if you, the forgetful programmer, didn&#x27;t bother to explicitly return a value:&quot;<p>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.<p><pre><code> cat &lt;&lt;eof &gt;1.c int main() { printf(&quot;Hello World!\n&quot;); } eof cc -Wall -std=c89 -pedantic -ansi 1.c .&#x2F;a.out 1.c: In function &#x27;main&#x27;: 1.c:4:10: warning: implicit declaration of function &#x27;printf&#x27; [-Wimplicit-function-declaration] 4 | printf(&quot;Hello World!\n&quot;); | ^~~~~~ 1.c:4:10: warning: incompatible implicit declaration of built-in function &#x27;printf&#x27; 1.c:1:1: note: include &#x27;&lt;stdio.h&gt;&#x27; or provide a declaration of &#x27;printf&#x27; +++ |+#include &lt;stdio.h&gt; 1 | 1.c:5:2: warning: control reaches end of non-void function [-Wreturn-type] 5 | } | ^</code></pre> As a learning exercise I try to silence the warnings one by one.<p>Instead of just including &lt;stdio.h&gt;, which teaches me nothing, I find the prototype string and insert it the .c file using a short script something like the following<p><pre><code> #!&#x2F;bin&#x2F;sh test $# = 1||exec echo usage: $0 function grep -r &quot; $1(&quot; &#x2F;usr&#x2F;include&#x2F;* 2&gt;&#x2F;dev&#x2F;null|sed &#x27;s&#x2F;.*:&#x2F;&#x2F;;s&#x2F; *&#x2F;&#x2F;&#x27; </code></pre> This enables me to learn that the printf protoype uses __restrict instead of restrict, and consequently a portability note:<p>On Linux, __restrict is defined in &#x2F;usr&#x2F;include&#x2F;features.h<p>On NetBSD, __restrict is defined in &#x2F;usr&#x2F;include&#x2F;sys&#x2F;cdefs.h<p>Now, with the printf() prototype included<p><pre><code> sed \$r1.c &lt;&lt;eof &gt;2.c int printf(const char *restrict, ...); eof cc -Wall -std=c89 -pedantic -ansi 2.c .&#x2F;a.out 2.c: In function &#x27;main&#x27;: 2.c:5:2: warning: control reaches end of non-void function [-Wreturn-type] 5 | } | ^ </code></pre> 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.<p><pre><code> sed 4r2.c &lt;&lt;eof &gt;3.c exit(0); eof cc -Wall -std=c89 -pedantic -ansi 3.c .&#x2F;a.out 3.c: In function &#x27;main&#x27;: 3.c:5:35: warning: implicit declaration of function &#x27;exit&#x27; [-Wimplicit-function-declaration] 5 | printf(&quot;Hello World!\n&quot;);exit(0); | ^~~~ 3.c:5:35: warning: incompatible implicit declaration of built-in function &#x27;exit&#x27; 3.c:1:1: note: include &#x27;&lt;stdlib.h&gt;&#x27; or provide a declaration of &#x27;exit&#x27; +++ |+#include &lt;stdlib.h&gt; 1 | </code></pre> Find the prototype for exit() and add it in, instead of just blindly including &lt;stdlib.h&gt;.<p><pre><code> sed 2r3.c &lt;&lt;eof &gt;4.c void exit(int); eof cc -Wall -std=c89 -pedantic -ansi 4.c .&#x2F;a.out</code></pre>
评论 #28954157 未加载
perryizgr8超过 3 年前
Tldr:<p>Not returning a value from main() is undefined behavior in ANSI C. So compiler will do whatever it likes. It will return 0 or 42 or crash. In this case, gcc just replaces printf with something else it likes more.
评论 #28963123 未加载
moron4hire超过 3 年前
&quot;I wanna be close to the metal. I wanna be in complete control. I wanna code in C!&quot;<p>Yeah. Right.
SavantIdiot超过 3 年前
In other news: man discovers compilers do things you don&#x27;t expect when you operate out of spec.<p>Jeeze, don&#x27;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.
matheusmoreira超过 3 年前
Compiler optimization is really annoying sometimes. It&#x27;s allowed to assume that functions with the same name as standard library functions behave according to standard. They&#x27;ll swap out printf calls for puts if they don&#x27;t have a format. The compiler just knows it can do that. Sure, it optimizes things but it gets to the point the code no longer reflects what&#x27;s written on the source file. Try to hook into printf and it won&#x27;t work because it&#x27;s not actually calling printf.<p>Even on freestanding environments they can and will generate calls to memcpy and memmove. That&#x27;s insane...
评论 #28952963 未加载
评论 #28953534 未加载