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

科技回声

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

GitHubTwitter

首页

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

资源链接

HackerNews API原版 HackerNewsNext.js

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

Everything I wish I knew when learning C

738 点作者 bubblehack3r超过 2 年前

51 条评论

DSMan195276超过 2 年前
I like it, but the array details are a little bit off. An actual array does have a known size, that&#x27;s why when given a real array `sizeof` can give the size of the array itself rather than the size of a pointer. There&#x27;s no particular reason why C doesn&#x27;t allow you to assign one array to another of the same length, it&#x27;s largely just an arbitrary restriction. As you noted, it already has to be able to do this when assigning `struct`s.<p>Additionally a declared array such as `int arr[5]` does actually have the type `int [5]`, that is the array type. In most situations that decays to a pointer to the first element, but not always, such as with `sizeof`. This becomes a bit more relevant if you take the address of an array as you get a pointer to an array, Ex. `int (*ptr)[5] = &amp;arr;`. As you can see the size is still there in the type, and if you do `sizeof *ptr` you&#x27;ll get the size of the array.
评论 #33780249 未加载
评论 #33780843 未加载
评论 #33775869 未加载
评论 #33776828 未加载
评论 #33774856 未加载
评论 #33786100 未加载
评论 #33785020 未加载
评论 #33776518 未加载
nayuki超过 2 年前
&gt; Everything I wish I knew when learning C<p>By far my biggest regret is that the learning materials I was exposed to (web pages, textbooks, lectures, professors, etc.) did not mention or emphasize how insidious undefined behavior is.<p>Two of the worst C and C++ debugging experiences I had followed this template: Some coworker asked me why their function was crashing, I edit their function and it sometimes crashes or doesn&#x27;t depending on how I rearrange lines of code, and later I figure out that some statement near the top of the function corrupted the stack and that the crashes had nothing to do with my edits.<p>Undefined behavior is deceptive because the point at which the program state is corrupted can be arbitrarily far away from the point at which you visibly notice a crash or wrong data. UB can also be non-deterministic depending on OS&#x2F;compiler&#x2F;code&#x2F;moonphase. Moreover, &quot;behaving correctly&quot; is one legal behavior of UB, which can fool you into believing your program is correct when it has a hidden bug.<p>A related post on the HN front page: <a href="https:&#x2F;&#x2F;predr.ag&#x2F;blog&#x2F;falsehoods-programmers-believe-about-undefined-behavior&#x2F;" rel="nofollow">https:&#x2F;&#x2F;predr.ag&#x2F;blog&#x2F;falsehoods-programmers-believe-about-u...</a> , <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=33771922" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=33771922</a><p>My own write-up: <a href="https:&#x2F;&#x2F;www.nayuki.io&#x2F;page&#x2F;undefined-behavior-in-c-and-cplusplus-programs" rel="nofollow">https:&#x2F;&#x2F;www.nayuki.io&#x2F;page&#x2F;undefined-behavior-in-c-and-cplus...</a><p>The take-home lesson about UB is to only rely on following the language rules strictly (e.g. don&#x27;t dereference null pointer, don&#x27;t overflow signed integer, don&#x27;t go past end of array). Don&#x27;t just assume that your program is correct because there were no compiler warnings and the runtime behavior passed your tests.
评论 #33775979 未加载
评论 #33783304 未加载
评论 #33779481 未加载
评论 #33776690 未加载
评论 #33776050 未加载
评论 #33775095 未加载
评论 #33774815 未加载
评论 #33775658 未加载
unwind超过 2 年前
This looks decent, but I&#x27;m (highly) opposed to recommending `strncpy()` as a fix for `strcpy()` lacking bounds-checking. That&#x27;s not what it&#x27;s for, it&#x27;s weird and should be considered as obosolete as `gets()` in my opinion.<p>If available, it&#x27;s much better to do the `snprintf()` way as I mentioned in a comment last week, i.e. replace `strcpy(dest, src)` with `snprintf(dst, sizeof dst, &quot;%s&quot;, src)` and always remember that &quot;%s&quot; part. Never put src there, of course.<p>There&#x27;s also `strlcpy()` on some systems, but it&#x27;s not standard.
评论 #33773654 未加载
评论 #33774122 未加载
评论 #33774762 未加载
评论 #33776680 未加载
评论 #33785980 未加载
krylon超过 2 年前
When I first learned C - which also was my first contact with programming at all - I did not understand how pointers work, and the book I was using was not helpful at all in this department. I only &quot;got&quot; pointers like three or four years later, fortunately programming was still a hobby at that point.<p>Funnily when I felt confident enough to tell other people about this, several immediate started laughing and told me what a relief it was to hear they weren&#x27;t the only ones with that experience.<p>Ah, fun times.<p>EDIT: One book I found invaluable when getting serious about C was &quot;The New C Standard: A Cultural and Economic Commentary&quot; by Derek Jones (<a href="http:&#x2F;&#x2F;knosof.co.uk&#x2F;cbook" rel="nofollow">http:&#x2F;&#x2F;knosof.co.uk&#x2F;cbook</a>). You can read it for free because the book ended up being to long for the publisher&#x27;s printing presses or something like that. It&#x27;s basically a sentence-by-sentence annotated version of the C standard (C99 only, though) that tries to explain what the respective sentence <i>means</i> to C programmers and compiler writers and how other languages (mostly C++) deal with the issue at hand, but also how this impacts the work of someone developing coding guidelines for large teams of programmers (which was how the author made a living at the time, possibly still is). It&#x27;s more than 1500 pages and a very dense read, but it is incredibly fine-grained and in-depth. Definitely not suitable for people who are just learning C, but if you have read &quot;Expert C Programming: Deep C Secrets&quot; and found it too shallow and whimsical, this book was written for you.
评论 #33775678 未加载
评论 #33776586 未加载
评论 #33776132 未加载
评论 #33778257 未加载
评论 #33775649 未加载
评论 #33780996 未加载
评论 #33776251 未加载
quietbritishjim超过 2 年前
&gt; Declaring a variable or parameter of type T as const T means, roughly, that the variable cannot be modified.<p>I would add &quot;... cannot be modified <i>through that pointer</i>&quot;. (Yes, in fairness, they did say &quot;roughly&quot;.) For example consider the following:<p><pre><code> void foo(int* x, const int* y) { printf(&quot;y before: %d\n&quot;, *y); *x = 3; printf(&quot;y after: %d\n&quot;, *y); } </code></pre> This will print two different values if you have `int i = 1` and you call `foo(&amp;i, &amp;i)`. This is the classic C aliasing rule. The C standard guarantees that this works even under aggresive optimisation (in fact certain optimisations are prevented by this rule), whereas the analogous Fortrain wouldn&#x27;t be guaranteed to work.
评论 #33774278 未加载
评论 #33774187 未加载
评论 #33774182 未加载
limaoscarjuliet超过 2 年前
I was born in &#x27;74 so the last generation to start with C and go to other, higher-level, languages like Python or JavaScript. Going in this direction was natural. I was amazed by all the magic the higher-level languages offered.<p>Going the other direction is a bit more difficult apparently. &quot;What do you mean it does not do that?&quot;. Interesting perspective indeed!
评论 #33782186 未加载
评论 #33777834 未加载
评论 #33779889 未加载
评论 #33820288 未加载
评论 #33778269 未加载
评论 #33780623 未加载
hddqsb超过 2 年前
Some constructive feedback:<p><i>&gt; Here are the absolute essential flags you may need.</i><p>I highly recommend including `-fsanitize=address,undefined` in there (docs: <a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc&#x2F;Instrumentation-Options.html" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc&#x2F;Instrumentation-Options.h...</a>).<p>(Edit: But probably not in release builds, as @rmind points out.)<p><i>&gt; The closest thing to a convention I know of is that some people name types like my_type_t since many standard C types are like that</i><p>Beware that names beginning with &quot;int&quot;&#x2F;&quot;uint&quot; and ending with &quot;_t&quot; are reserved in &lt;stdint.h&gt;.<p>[Edited; I originally missed the part about &quot;beginning with int&#x2F;uint&quot;, and wrote the following incorrectly comment: &quot;That shouldn&#x27;t be recommended, because names ending with &quot;_t&quot; are reserved. (As of C23 they are only &quot;potentially reserved&quot;, which means they are only reserved if an implementation actually uses the name: <a href="https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;c&#x2F;language&#x2F;identifier" rel="nofollow">https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;c&#x2F;language&#x2F;identifier</a>. Previously, defining <i>any</i> typedef name ending with &quot;_t&quot; technically invokes undefined behaviour.)&quot;]<p>The post never mentions undefined behaviour, which I think is a big omission (especially for programmers coming from languages with array index checking).<p><i>&gt; void main() {</i><p>As @vmilner mentioned, this is non-standard (reference: <a href="https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;c&#x2F;language&#x2F;main_function" rel="nofollow">https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;c&#x2F;language&#x2F;main_function</a>). The correct declaration is either `int main(void)` or the argc+argv version.<p>(I must confess that I am guilty of using `int main()`, which is valid in C++ but technically not in C: <a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;29190986&#x2F;is-int-main-without-void-valid-and-portable-in-iso-c" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;29190986&#x2F;is-int-main-wit...</a>).<p><i>&gt; You can cast T to const T, but not vice versa.</i><p>This is inaccurate. You can <i>implicitly convert</i> T* to const T*, but you need to use <i>an explicit cast</i> to convert from const T* to T*.
评论 #33775630 未加载
评论 #33775187 未加载
评论 #33774838 未加载
评论 #33773945 未加载
评论 #33774950 未加载
评论 #33773415 未加载
评论 #33773983 未加载
nayuki超过 2 年前
&gt; C has no environment which smooths out platform or OS differences<p>Not true - C has little environment, not no environment. For example, fopen(&quot;&#x2F;path&#x2F;file.txt&quot;, &quot;r&quot;) is the same on Linux and Windows. For example, uint32_t is guaranteed to be 32 bits wide, unlike plain int.<p>&gt; Each source file is compiled to a .o object file<p>Is this a convention that compilers follow, or are intermediate object files required by the C standard? Does the standard say much at all about intermediate and final binary code?<p>&gt; static<p>This keyword is funny because in a global scope, it reduces the scope of the variable. But in a function scope, it increases the scope of the variable.<p>&gt; Integers are very cursed in C. Writing correct code takes some care<p>Yes they very much are. <a href="https:&#x2F;&#x2F;www.nayuki.io&#x2F;page&#x2F;summary-of-c-cpp-integer-rules" rel="nofollow">https:&#x2F;&#x2F;www.nayuki.io&#x2F;page&#x2F;summary-of-c-cpp-integer-rules</a>
评论 #33775727 未加载
评论 #33780233 未加载
评论 #33782501 未加载
arendtio超过 2 年前
After learning C, one of the first projects I came into contact with, was the ID Tech 3 game engine [1]<p>On the one hand, it taught me how professional C programmers structure their code (extra functions to remove platform differences, specific code which is being shared between server and client to allow smooth predictions) and how incredible fast computers can be (thousands of operations within milliseconds), but it also showed me, how the same code can result in different executions due to compiler differences (tests pass, production crashes) and how important good debugging tools are (e.g. backtraces).<p>To this day I am very grateful for the experience and that ID decided to release the code as open source.<p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;id-Software&#x2F;Quake-III-Arena" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;id-Software&#x2F;Quake-III-Arena</a>
modernerd超过 2 年前
Love the intro and overview — looking forward to more!<p>These weren&#x27;t mentioned in the post but have been very helpful in my journey as a C beginner so far:<p>- Effective C by Robert C. Seacord. It covers a lot of the footguns and gotchas without assuming too much systems or comp-sci background knowledge. <a href="https:&#x2F;&#x2F;nostarch.com&#x2F;Effective_C" rel="nofollow">https:&#x2F;&#x2F;nostarch.com&#x2F;Effective_C</a> (Also, how can you not buy a book on C with Cthulhu on the cover written by a guy with _three_ “C”s in his name?)<p>- Tiny C Projects by Dan Gookin, for a “learn by doing” approach. <a href="https:&#x2F;&#x2F;www.manning.com&#x2F;books&#x2F;tiny-c-projects" rel="nofollow">https:&#x2F;&#x2F;www.manning.com&#x2F;books&#x2F;tiny-c-projects</a><p>- Exercism&#x27;s C language track: <a href="https:&#x2F;&#x2F;exercism.org&#x2F;tracks&#x2F;c" rel="nofollow">https:&#x2F;&#x2F;exercism.org&#x2F;tracks&#x2F;c</a><p>- Computer Systems, A Programmer&#x27;s Perspective by Randal E. Bryant and David R. O&#x27;Hallaron for a deeper dive into memory, caches, networking, concurrency and more using C, with plenty of practice problems: <a href="https:&#x2F;&#x2F;csapp.cs.cmu.edu&#x2F;" rel="nofollow">https:&#x2F;&#x2F;csapp.cs.cmu.edu&#x2F;</a>
0xbadcafebee超过 2 年前
More <i>Good projects to learn from</i>:<p><pre><code> - Busybox (https:&#x2F;&#x2F;github.com&#x2F;mirror&#x2F;busybox) - uClibc (https:&#x2F;&#x2F;git.uclibc.org&#x2F;uClibc&#x2F;tree&#x2F;) - musl (https:&#x2F;&#x2F;git.musl-libc.org&#x2F;cgit&#x2F;musl&#x2F;tree&#x2F;) - misc GNU tools (https:&#x2F;&#x2F;git.savannah.gnu.org&#x2F;cgit&#x2F;grep.git&#x2F;tree&#x2F;, https:&#x2F;&#x2F;git.savannah.gnu.org&#x2F;cgit&#x2F;findutils.git&#x2F;tree&#x2F;, etc) </code></pre> The first two are oriented towards embedded development, which I find leads to the simplest, most portable code. Those devs are absolute wizards.
vmilner超过 2 年前
This used to be my bible when doing full time C programming around 2000 (together with the standard docs) but I’m out of date with the latest standard updates (as is this) but it may still be of interest.<p><a href="https:&#x2F;&#x2F;c-faq.com&#x2F;" rel="nofollow">https:&#x2F;&#x2F;c-faq.com&#x2F;</a>
nadavision超过 2 年前
Thanks for submitting this. I&#x27;m teaching myself C so these high level overviews are super useful for improving my intuition. In the following example, shouldn&#x27;t there be an asterisk * before the data argument in the getData function call? The way I understand it the function is expecting a pointer so you would need to pass it a pointer of the data object.<p>&gt; &quot;If you want to “return” memory from a function, you don’t have to use malloc&#x2F;allocated storage; you can pass a pointer to a local data:<p>void getData(int *data) { data[0] = 1; data[1] = 4; data[2] = 9; }<p>void main() { int data[3]; getData(data); printf(&quot;%d\n&quot;, data[1]); } &quot;
评论 #33773379 未加载
评论 #33773443 未加载
评论 #33773690 未加载
评论 #33773391 未加载
lebuffon超过 2 年前
&quot; ... is often called the stack.&quot; &quot; integers are cursed&quot;<p>These statements and a few others made me uncomfortable. They imply, to me, that the author has too little knowledge of computer internals to be programming in C.<p>C does a wonderful job of looking like a high level language but it was designed to do low level stuff. There is an implicit assumption, to my mind, that the user has a deeper understanding of what is behind the &quot;curtain&quot; that is created by the compiler.<p>It almost seems like the there should a pre-requisite course like &quot;Introduction to Computer hardware&quot; before one is allowed to write a line of C.<p>Maybe I&#x27;m just too old...
评论 #33776374 未加载
评论 #33779580 未加载
评论 #33781695 未加载
评论 #33775260 未加载
评论 #33776217 未加载
评论 #33776473 未加载
评论 #33776403 未加载
pratk超过 2 年前
One C idiom that I found pretty useful is Xmacros [1]. For instance, it&#x27;s used extensively in GCC code-base (.def files).<p>[1] <a href="https:&#x2F;&#x2F;www.drdobbs.com&#x2F;the-new-c-x-macros&#x2F;184401387" rel="nofollow">https:&#x2F;&#x2F;www.drdobbs.com&#x2F;the-new-c-x-macros&#x2F;184401387</a>
评论 #33785427 未加载
jhallenworld超过 2 年前
I&#x27;ve been programming in C forever, one advantage is that the language has not evolved much (especially compared with C++), but it has evolved.<p>There was the big K&amp;R C to ANSI C function declaration transition. For portable code, you used K&amp;R C well into the 90s (because older machines only had the K&amp;R compiler), or used ugly macros to automatically convert from ANSI to K&amp;R.<p>Another was the addition of &#x27;const&#x27; to the language. It used to be said that const was a virus: once you start using it, you need to use it universally in your entire code-base.<p>A more recent big one is stdint.h (types like uint32_t). To correctly use these types you must also use the macros in inttypes.h for scanf and printf conversions. IMHO, they both should have been in the same header files, they go along with each other.<p>So in the old days, you would say: unsigned int x; printf(&quot;%u\n&quot;, x);<p>But now, you should tediously say: uint32_t x; printf(&quot;%&quot;PRIu32&quot;\n&quot;, x);<p>(Because uint32_t might be defined as a long even if it&#x27;s the same size as in int, so you will get compiler warnings. You could use %lu, but then you get compiler warnings the other way.)<p>Another: On UNIX, we don&#x27;t have to worry about &quot;wide&quot; characters (use UTF-8 instead) and wide strings, but you certainly do on Windows. &quot;Wide&quot; characters are obsolete but Windows is stuck with them since they are built into the OS.
评论 #33782754 未加载
评论 #33780164 未加载
einpoklum超过 2 年前
Half of the items the poster lists as &quot;wish I&#x27;d known&quot; are things which were literally part of the curriculum when I taught C at my alma mater (Technion IIT, Haifa). And then, some things are better not know - like cppreference, which would just confuse you with a lot of C++, which is interesting, but not relevant. Also, there are some nitpicks to make, like about array decay etc.<p>More generally:<p>We can&#x27;t expect to know a lot of context before learning anything. You have to learn things in _some_ order. It&#x27;s better to know C when you study PDP assembly, and at the same time it&#x27;s better to already know PDP assembly when you study C - as you have insight into the motivation of what&#x27;s possible via the language syntax itself. Same thing for Calculus and Topology: The latter course helped me understand and generalize a lot of what we had done in the former, but without the former, I wouldn&#x27;t have had proper motivation for the latter, which might have seemed like useless sophistry.
评论 #33775197 未加载
user3939382超过 2 年前
The couple of times I tried to really learn C I ran into the same problems. I started by trying to answer two questions: what are the modern features of C that I need to learn to use it, and what style&#x2F;rules should I follow.<p>What I found is a body of several C spec updates that are each defined in reference to previous C spec updates. So I&#x27;m supposed to... ? Learn C from the 70s and then study each version update and mentally diff everything to figure out what C is now?<p>Then in terms of rules and style, unlike when K&amp;R C was published, I couldn&#x27;t find any authority. Actually what I see is that even programmers who have been writing C for many years frequently debate what practices are correct vs not. You can see it in this very thread. Every language has this, but I&#x27;ve seen it much more with C than other languages.<p>Actually learning the material for me is hard when I can&#x27;t even get a firm handle on what it is I&#x27;m supposed to learn.
评论 #33774919 未加载
评论 #33781398 未加载
pjc50超过 2 年前
The elderly &quot;C Traps and Pitfalls&quot; <a href="http:&#x2F;&#x2F;www.literateprogramming.com&#x2F;ctraps.pdf" rel="nofollow">http:&#x2F;&#x2F;www.literateprogramming.com&#x2F;ctraps.pdf</a> was an extremely helpful book when I was learning C, although I don&#x27;t know how well it&#x27;s held up.
评论 #33775830 未加载
BeetleB超过 2 年前
The one thing missing from this list: Compiler optimizations can have undesirable effects.<p>A trivial example I ran into in an older job: I was compiling a program that relied on libm.so (the standard math library you get when including math.h). Now I wanted the code to use my own custom libm.so - not the one that was installed in &#x2F;usr&#x2F;lib or wherever, so I ensured it was dynamically compiled.<p>My code had some calls like:<p><pre><code> int x = sin(3.2); </code></pre> During compilation, it computed sin(3.2) using the system libm. Notably, it would <i>not</i> use the sine function in my custom libm.so (and indeed, I needed it to!)<p>And IIRC, even -O0 was not enough to prevent this from happening. I had to go through the man page to figure out which compiler flags would prevent it.<p>(I don&#x27;t recall if this was gcc or icc).
评论 #33781079 未加载
caerwy超过 2 年前
I&#x27;d recommend also reading Rob Pike&#x27;s Notes on Programming in C, <a href="http:&#x2F;&#x2F;doc.cat-v.org&#x2F;bell_labs&#x2F;pikestyle" rel="nofollow">http:&#x2F;&#x2F;doc.cat-v.org&#x2F;bell_labs&#x2F;pikestyle</a>
评论 #33781964 未加载
curling_grad超过 2 年前
&quot;Teaching C&quot; seems to be a good read too: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=32798826" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=32798826</a>
nottorp超过 2 年前
C is easier if you first learn assembler for an architecture or two :)
评论 #33774483 未加载
评论 #33774231 未加载
fastaguy88超过 2 年前
I find this article very strange, perhaps because I started using &#x27;c&#x27; so long ago. To the bullet points:<p>(1) In general, &#x27;c&#x27; is always &#x27;c&#x27; at the command line, regardless of the platform.<p>(2) yes, there are options and build tools, but cc my_program.c -o my_program works fine. I have a very hard time figuring out how to compile&#x2F;run java.<p>(3) hard to see how this has anything to do with &#x27;C&#x27;, vs any other compiled language.<p>(4) so?? I would think I would be more concerned about how to use &#x27;c&#x27; for my problem, without worrying about how to use &#x27;c&#x27; to solve some other problem. It is hard for me to understand why a language that can do many things is more problematic than a language that only does a few things.<p>My sense is that reading this article makes things harder, not easier. Most people do not care whether an int is 32 or 64 bits.<p>I won&#x27;t argue that copying things (that are not ints or floats) needs to be understood, but many popular languages (specifically python) have the same problem. Understanding the difference between a reference and a value is important for most languages.<p>There are different schools of thought -- those that can imagine lots of issues after reading the documentation, vs those that simply try writing code and start exploring edge cases when something breaks. I learn faster by trying things, and rarely encounter the edge-case issues.
评论 #33775891 未加载
评论 #33776335 未加载
spacedcowboy超过 2 年前
‘ You can’t extend structs or do anything really OO-like, but it’s a useful pattern to think with’<p>That’s not quite true. If you define 2 structs so that they start the same (eg: both with “int x; int y” in your example), pointers can be passed to functions with either struct type. You can use this to add fields (eg: int z) to structures, and extend a 2d vector into a 3d one…<p>With a bit of creative thought, and constructive use of pointer-to-functions, you can do quite a bit of OOP stuff in C.
评论 #33785440 未加载
评论 #33774698 未加载
评论 #33775909 未加载
评论 #33775057 未加载
评论 #33783461 未加载
MisterTea超过 2 年前
&gt; I get an int* value which has 5 ints allocated at it.<p>Not crazy about this array explanation. Better wording would be: &quot;I get a memory address that points to the first byte of a chunk of memory that is large enough to hold 5 ints and tagged as int&quot;<p>&gt; Essential compiler flags<p>Nitpick, but this is only true if you are on a gcc&#x2F;clang platform.<p>&gt; If you want to “return” memory from a function, you don’t have to use malloc&#x2F;allocated storage; you can pass a pointer to a local data<p>It should be specified the memory must be passed by the caller for this to work. You can&#x27;t create a var in a called function and return that (you can but you will get undefined behavior as that memory is up for grabs after the function returns).<p>&gt; Integers are very cursed in C. Writing correct code takes some care.<p>Cursed how? No explanation.<p>Overall this article is not very good. I would add these to the lists:<p>General resources: Read the K&amp;R book. Read the C spec. Be familiar with the computer architectures you are working on.<p>Good projects to learn from: Plan 9. Seriously. It&#x27;s an entire OS that was designed to be as simple as possible by the same people who made Unix and the C.
评论 #33774293 未加载
andrewmcwatters超过 2 年前
The older I got, the more I realized you seem to be heavily disadvantaged by not having some rudimentary understanding of assembly when using C.<p>When you do have such an understanding, some small details, like declaring stack variables at the top of functions in ANSI C, become obvious.
评论 #33776866 未加载
yevpats超过 2 年前
Previously (recently) discussed on HN on why not to use c&#x2F;c++ - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=32905885" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=32905885</a>
twawaaay超过 2 年前
The most important thing I had to learn when I started on hardcore ANSI C projects (large embedded business critical application) was to really learn to build abstractions.<p>C has few tools to help you with this and so it is super important to get the most of what is available.<p>Another lesson is that idioms are very useful in C and cut a ton of time. For most or all repeatable tasks there should be conventions for how to implement it and how to use it.<p>These are useful in any programming language and environment but I think are especially useful in C where you are on your own when structuring your application.
wiseowise超过 2 年前
Where is the most important part: build tools and libraries?
manv1超过 2 年前
The reason you use specific sizes for types (int8, int16, uint16, etc) is so you know how to read&#x2F;write them when you move your data between platforms.<p>x86 is little endian. ARM apparently can be configured to be either.<p>In real code there should be readXXX and writeXXX functions that read&#x2F;write data from disk&#x2F;network and do the byte swapping in there.<p>You could also just convert everything to JSON, but you&#x27;re trading space for complexity&#x2F;time.
评论 #33779675 未加载
fsloth超过 2 年前
I would add to this: 1. Visual Studio debugger is really, really good and you should use it to step through your program (or equivalent IDE based workflow). 2. Learn to compile your code with memory safeguards and use the tooling around them. Specific depends on the platform. On POSIX address sanitizer is good I hear. On Windows you can use the debug CRT and gflags to instrument your binary really well.
评论 #33776362 未加载
评论 #33775214 未加载
alexandreyc超过 2 年前
After more than a decade without writing any C code, I&#x27;m currently reading &quot;C Programming: A modern Approach&quot; by K. N. King (<a href="http:&#x2F;&#x2F;www.knking.com&#x2F;books&#x2F;c2&#x2F;" rel="nofollow">http:&#x2F;&#x2F;www.knking.com&#x2F;books&#x2F;c2&#x2F;</a>) and I found it very good. I think it&#x27;s a better modern alternative to the K&amp;R.
评论 #33775681 未加载
vmilner超过 2 年前
Is<p><pre><code> void main() Still non-standard in C?</code></pre>
评论 #33773701 未加载
nwellnhof超过 2 年前
I wouldn&#x27;t recommend fixed-size integers in general. Most of the time you want size_t or the lesser-known, signed ptrdiff_t. More often than not, integers are array sizes or indices, so size_t is the best type to use. In other cases, int is practically the same as int32_t and long long the same as int64_t except for really exotic platforms.
评论 #33775499 未加载
ErikCorry超过 2 年前
Never use -Og for debug builds. It doesn&#x27;t work. Use -O0.<p>If you try to debug a -Og built program you will not be able to print locals because the optimizer has removed them. People blame their debugger.<p>It&#x27;s my humble opinion that -Og should be an alias for -O0. Broken for decades it&#x27;s time to stop pretending it works.
torstenvl超过 2 年前
Decent article. A couple minor points:<p>c89 or c99, not c98.<p>Plain static variables aren&#x27;t thread-safe by default, true, but there&#x27;s also _Thread_local
评论 #33773845 未加载
glonq超过 2 年前
My college taught us pascal and x86 asm before teaching us C. I think that was perfect because &quot;bookending&quot; it with a high-level language and a low-level one helped put C in perspective nicely. Knowing asm definitely helped to demystify pointers in C, which is usually a stumbling block for novice programmers.
_ache_超过 2 年前
&gt; You can cast T to const T, but not vice versa.<p>Humm, actually, you can. But guess what ? Modification of the underlying data is an UB !
评论 #33776852 未加载
评论 #33774224 未加载
willfiveash超过 2 年前
I still remember when a co-worker told me that the biggest problem with C is that programmers are terrible at memory management. Given the number of memory corruption bugs I encountered in 27 years of working with C, I have to say that rings true.
wyldfire超过 2 年前
&gt; -Werror to turn warnings into errors. I recommend always turning on at least -Werror=implicit, which ensures calling undeclared functions results in an error(!)<p>&quot;Implicit declarations&quot; is such a frustrating &quot;feature&quot; of C. Thankfully, in more recent clang builds this warning is enabled by default.
sfusato超过 2 年前
I wish I&#x27;d have known how bad everyone was in it, not just me...
Hadarai5超过 2 年前
This post is also a list of reasons why everyone thinking seriously about becoming computer scientists should start nowhere else than with C
badrabbit超过 2 年前
I&#x27;ll just say that if you have to write C in 2022&#x2F;23 then you should learn+automate fuzz testing with confirmation of coverage.
wheelerof4te超过 2 年前
Here is another one:<p>A lot of things can be done without using malloc and free.<p>Use these functions to manage memory in large clusters. Let the compiler deal with the rest.
jmclnx超过 2 年前
Nice, slowly &quot;teaching&quot; someone at work c for use on AIX. I will send him the link. I am not a very good teacher :)
评论 #33777899 未加载
评论 #33773498 未加载
hujun超过 2 年前
this is a good a good blog, although I wonder is there any good up-to-date free online resource to learn C for experienced programmer (I learned C many years ago, but never use it seriously and forgot much of it)? I searched around, the results are either for beginner, or seems out-dated
felipelalli超过 2 年前
Is there a similar article but to Rust?
评论 #33775026 未加载
dahfizz超过 2 年前
&gt; The sizes of arrays are not known in any useful way to C. When I declare a variable of type int[5] in a function, I don’t get a value of type int[5]; I get an int* value which has 5 ints allocated at it. Since this is just a pointer, the programmer, not the language, has to manage copying the data behind it and keeping it valid.<p>This is not quite correct. Assuming arrays == pointers is usually true enough, but it isn&#x27;t actually true. This[1] SO thread has some useful information in it, but the TLDR is that actual arrays are treated differently than pointers. You do get an object of type &quot;int array&quot; rather than &quot;int pointer&quot; when you do int[5].<p>The compiler does know the size of an array allocated like T a[n]. It does not, however, do any bounds checking for you.<p>[1] <a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;4607128&#x2F;in-c-are-arrays-pointers-or-used-as-pointers" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;4607128&#x2F;in-c-are-arrays-...</a>
ben_bradley超过 2 年前
I started learning C around when ANSI C came out, and learned much of this in self defense. I&#x27;m glad I decided to learn C++ in recent years, it has fixes for so many things (like pass by reference instead of passing pointers, const values can be used to define array sizes though it&#x27;s better to use vectors anyway, etc.), but that&#x27;s off topic.<p>A few things I didn&#x27;t see mentioned: Add multiple inclusion guards to every header file you write, it saves multiply-defined errors and such:<p>file mygreatheaderfile.h:<p>#ifndef MYGREATHEADERFILE_H<p>#define MYGREATHEADERFILE_H<p>&#x2F;* insert usual header file content here <i>&#x2F;<p>#endif &#x2F;</i> #ifndef MYGREATHEADERFILE_H *&#x2F;<p>Most (all?) compilers have a &quot;don&#x27;t include this file more than once&quot; preprocessor directive, but from what I&#x27;ve seen they&#x27;re nonstandard and they vary, but using the above method always works.<p>If I have a &quot;complete program&quot; with a main function and other functions in one source file, I put main() at the end and put all functions in the order they are called, that way there&#x27;s no need for function prototypes (except for recursion) as there would be if main() is the first function in the file. None of the C books I&#x27;ve read said you could do this, but when I figured it out I thought yeah, it&#x27;s just like Pascal and assembly, you have to define something before you use it, but you can make the first occurrence be the function definition and not have to have a separate prototype.<p>As for naming and capitalizing, as the document said, there&#x27;s no standard&#x2F;convention of camelCase vs. snake_case, but all macro names using #define are by convention in ALL_CAPS. That way it&#x27;s easy to tell a MAX(x, y) macro from a max (x, y) function, and you can eventually learn why never to write such perverse things as MAX (x++, y++). Trace through the expansion to see why (and see why it&#x27;s better to use a function instead, or in C++ a template): #define MAX(x,y) x&gt;y?x:y<p>Equals comparison&#x2F;assignment and if statements: One of the most common and insidious errors in C is accidentally doing an assignment (=) instead of comparison (==). Modern C compilers (the ones with integrated C++ compilers, see below) will give a warning when they see this, but still, if one of these is a constant, put the constant on the left so it will give an ERROR if you accidentally try to assign something to the constant as in if (5 = n) instead of what may feel natural but be wrong (and compile fine with an old compiler!), if (n = 5). There are other gotchas like this, but I can&#x27;t think of them all, and there&#x27;s probably too many to post here anyway. I do see &quot;undefined behavior&quot; discussed. Be sure to make backups before running your code.<p>If you need to do maintenance using some original C compiler for an embedded controller from 30 years ago (or indeed modern C as is still popular in embedded systems), you really need to know all these ins and outs, and I might be convinced to help for an appropriately high hourly amount, but virtually every C compiler nowadays is part of a C++ compiler, and you can do much of this stuff in C++ using better code practices, resulting in fewer bugs.
sylware超过 2 年前
C syntax is already too rich and complex.<p>typedef&#x2F;enum&#x2F;(_Generic)&#x2F;etc should go (fix&#x2F;cleanup function pointer type declaration). Only sized primitive types (u32&#x2F;s32,u64&#x2F;s64,f32&#x2F;f64 or udw&#x2F;sdw,uqw&#x2F;sqw,fdw&#x2F;fqw...). We would have only 1 loop statement &quot;loop{}&quot;, no switch. I am still thinking about &quot;anonymous&quot; code blocks for linear-code variable sub-scoping (should be small compile-unit local function I guess). No integer promotion, no implicit cast (except for void* and maybe for literals like rust) with explicit compile-time&#x2F;runtime casts (not with that horrible c++ syntax). Explicit compile-time&#x2F;&quot;scoped&quot; runtime constants: currently it is only &quot;scoped&quot; runtime, with on some optimization passes to detect if the constant would be compile time. extern properly enforced for function plz (aka write proper headers with proper switches), and maybe &quot;local&quot; instead of &quot;static&quot; for compile-unit-only functions since all functions in a compile-unit are &quot;static&quot; anyway like global variables.<p>&quot;Non-standard&quot;: ban attributes like binary format visibility (let the linker handle the fine details), packed (if your struct is packed and not compatible with the C struct, it should be byte defined, with proper pointer casts), etc.<p>Fix the preprocessor variable argument macro for good (now it is a mess because of gcc way and c++ ISO way, I guess we will stick to gcc way).<p>With the preprocessor and some rigorous coding, we should be able to approximate that with a &quot;classic&quot; C compiler, since we mostly remove stuff. Was told that many &quot;classic&quot; C compiler could output optional warnings about things like implicit casts and integer promotions.<p>In theory, this should help writting a naive &quot;C-&quot; compiler much more easily than a &quot;classic&quot; C compiler and foster real life alternatives.<p>I am sure stuff I said are plain broken as I did not write a C compiler.<p>I wonder how far rust is from this &quot;C-&quot; as it is expected to have a much less rich and complex, but more constraint, syntax than C.
评论 #33776035 未加载
评论 #33774091 未加载