Live data from Hacker News

Everything I wish I knew when learning C

tmewett.com

31–40 of 401 posts

Re: Everything I wish I knew when learning C

#31
post #27

Earlier quoted context omitted.

It's not just a memorization trick; that's exactly what the statement means. If you do int *x, y; You're saying that both *x and y are integers.

... which is why I never understood why this is the convention rather than int* x, y. Does somebody know?

You must've misunderstood, your statement looks like both x and y are `int *`, but in fact only x is an `int *`, while y is an `int`.

Re: Everything I wish I knew when learning C

#32
post #7

This looks decent, but I'm (highly) opposed to recommending `strncpy()` as a fix for `strcpy()` lacking bounds-checking. That's not what it's for, it's weird and should be considered as obosolete as `gets()` in my opinion. If available, it'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, "%s", src)` and always remember tha…

strncpy does have its odd and rare use-case, but 100% agree that it is not at all a “fix” for strcpy, it’s not designed for that purpose, and unsuited to it, being both unsafe (does not guarantee NUL-termination) and unnecessary costly (fills the destination with NULs). The strn* category was generally designed for fixed-size NUL-padded content (though not all of them because why be coherent?), the entire item is inc…

[deleted]

Re: Everything I wish I knew when learning C

#33
> I get an int* value which has 5 ints allocated at it.

Not crazy about this array explanation. Better wording would be: "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"

> Essential compiler flags

Nitpick, but this is only true if you are on a gcc/clang platform.

> If you want to “return” memory from a function, you don’t have to use malloc/allocated storage; you can pass a pointer to a local data

It should be specified the memory must be passed by the caller for this to work. You can'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).

> Integers are very cursed in C. Writing correct code takes some care.

Cursed how? No explanation.

Overall this article is not very good. I would add these to the lists:

General resources: Read the K&R book. Read the C spec. Be familiar with the computer architectures you are working on.

Good projects to learn from: Plan 9. Seriously. It's an entire OS that was designed to be as simple as possible by the same people who made Unix and the C.

Re: Everything I wish I knew when learning C

#34
post #7

This looks decent, but I'm (highly) opposed to recommending `strncpy()` as a fix for `strcpy()` lacking bounds-checking. That's not what it's for, it's weird and should be considered as obosolete as `gets()` in my opinion. If available, it'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, "%s", src)` and always remember tha…

strncpy does have its odd and rare use-case, but 100% agree that it is not at all a “fix” for strcpy, it’s not designed for that purpose, and unsuited to it, being both unsafe (does not guarantee NUL-termination) and unnecessary costly (fills the destination with NULs). The strn* category was generally designed for fixed-size NUL-padded content (though not all of them because why be coherent?), the entire item is inc…

Then there are strn*_s since C11 (and available before that on many platforms) which do exactly what you want.

Re: Everything I wish I knew when learning C

#35
post #6

Some constructive feedback: > Here are the absolute essential flags you may need. I highly recommend including `-fsanitize=address,undefined` in there (docs: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.h... ). (Edit: But probably not in release builds, as @rmind points out.) > 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…

How can a (badly chosen) typedef name trigger _undefined behavior_, and not just, say, a compilation error...?

I find it difficult to imagine what that would even mean.

Re: Everything I wish I knew when learning C

#36
Love the intro and overview — looking forward to more!

These weren't mentioned in the post but have been very helpful in my journey as a C beginner so far:

- 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. https://nostarch.com/Effective_C (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?)

- Tiny C Projects by Dan Gookin, for a “learn by doing” approach. https://www.manning.com/books/tiny-c-projects

- Exercism's C language track: https://exercism.org/tracks/c

- Computer Systems, A Programmer's Perspective by Randal E. Bryant and David R. O'Hallaron for a deeper dive into memory, caches, networking, concurrency and more using C, with plenty of practice problems: https://csapp.cs.cmu.edu/

Re: Everything I wish I knew when learning C

#37
post #27

Earlier quoted context omitted.

It's not just a memorization trick; that's exactly what the statement means. If you do int *x, y; You're saying that both *x and y are integers.

... which is why I never understood why this is the convention rather than int* x, y. Does somebody know?

Because now you've got an int pointer and an int. The star associates with the right, not left.

I prefer to use the variant you described though, because it feels more natural to associate the pointer with the type itself. As far as I know, the only pitfall is in the multiple declaration thing so I just don't use it.

IMO, it's also more readable in this case:

    int *get_int(void);
    int* get_int(void);
The second one more clearly shows that it returns a pointer-to-int.

Re: Everything I wish I knew when learning C

#38
post #6

Some constructive feedback: > Here are the absolute essential flags you may need. I highly recommend including `-fsanitize=address,undefined` in there (docs: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.h... ). (Edit: But probably not in release builds, as @rmind points out.) > 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…

C spec:

>That shouldn't be recommended, because names ending with "_t" are reserved.

Also C spec naming new things:

>_Atomic _Bool

I'm glad to see the C folks have a sense of humor.

Re: Everything I wish I knew when learning C

#40
C syntax is already too rich and complex.

typedef/enum/(_Generic)/etc should go (fix/cleanup function pointer type declaration). Only sized primitive types (u32/s32,u64/s64,f32/f64 or udw/sdw,uqw/sqw,fdw/fqw...). We would have only 1 loop statement "loop{}", no switch. I am still thinking about "anonymous" 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/runtime casts (not with that horrible c++ syntax). Explicit compile-time/"scoped" runtime constants: currently it is only "scoped" 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 "local" instead of "static" for compile-unit-only functions since all functions in a compile-unit are "static" anyway like global variables.

"Non-standard": 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.

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).

With the preprocessor and some rigorous coding, we should be able to approximate that with a "classic" C compiler, since we mostly remove stuff. Was told that many "classic" C compiler could output optional warnings about things like implicit casts and integer promotions.

In theory, this should help writting a naive "C-" compiler much more easily than a "classic" C compiler and foster real life alternatives.

I am sure stuff I said are plain broken as I did not write a C compiler.

I wonder how far rust is from this "C-" as it is expected to have a much less rich and complex, but more constraint, syntax than C.

Post reply on HN