Live data from Hacker News

Everything I wish I knew when learning C

tmewett.com

41–50 of 401 posts

Re: Everything I wish I knew when learning C

#41

Decent article. A couple minor points: c89 or c99, not c98. Plain static variables aren't thread-safe by default, true, but there's also _Thread_local

I haven't written actual C code in decades. Did C11 get magic statics with thread-safe initialization like C++11? Does C even have non-trivial initialization of statics local variables?

C does have initialization of local variables, including static. It does not have any thread safety in standard for these, however, so no thread safe singletons. (You can get them initialized by linker or runtime safely, of course, e.g. ELF .bss and UCRT on Windows) You can use atomics to implement such a singleton if they are available.

This is one of the main reasons why C is more portable than C++.

Re: Everything I wish I knew when learning C

#42
> Declaring a variable or parameter of type T as const T means, roughly, that the variable cannot be modified.

I would add "... cannot be modified through that pointer". (Yes, in fairness, they did say "roughly".) For example consider the following:

    void foo(int* x, const int* y)
    {
        printf("y before: %d\n", *y);
        *x = 3;
        printf("y after: %d\n", *y);
    }
This will print two different values if you have `int i = 1` and you call `foo(&i, &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't be guaranteed to work.

Re: Everything I wish I knew when learning C

#44
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.

That only because bool was usually an old alias to int.. It's defined as alias to _Bool in stdbool.h, highly recommended.

Re: Everything I wish I knew when learning C

#45
post #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 integ…

There's a lot in "C", but I don't see anything in it that really isn't needed to serve its modern purpose.

In 2022 "C" is used as a portable assembly language. When you really need to control where and how memory is allocated, and represent data structures used directly by the hardware in a high-level language.

Re: Everything I wish I knew when learning C

#46
post #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.

The problem being that to trigger a compile error the compiler would have to know all its reserved type names ahead of time.

It is not required to do so, hence undefined behavior. You might get a wrong underlying type under that name.

Re: Everything I wish I knew when learning C

#47
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…

>sizeof dst

Note that this only works if dst is a stack allocated(in the same function) array and not a char *

Re: Everything I wish I knew when learning C

#48

Earlier quoted context omitted.

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.

Lol no. These are the Annex K stuff which Microsoft got into the standard, which got standardised with a different behaviour than Windows’ (so even on windows following the spec doesn’t work) and which no one else wants to implement at all.

And they don’t actually “do exactly what you want”, see for instance N1967 (“field experience with annex k”) which is less than glowing.

Re: Everything I wish I knew when learning C

#49
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.

The standard reserves several classes of identifiers, "_t" suffix [edit: with also "int"/"uint" prefix] is just one of several rules. Another rule is "All identifiers that begin with an underscore followed by a capital letter or by another underscore" (and also "All external identifiers that begin with an underscore").

Re: Everything I wish I knew when learning C

#50

Thanks for submitting this. I'm teaching myself C so these high level overviews are super useful for improving my intuition. In the following example, shouldn'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. > "If you want to “return” memory from a function, you don’t h…

No, it's correct. The asterisk is a little inconsistent, in that it means two opposite things. In the declaration it means "this is a pointer." However, in an expression , it means "this is the underlying type" and serves to dereference the pointer. int a = 5; int *x; // this is a pointer x = &a; int c = *x; // both c and *x are ints If it were *data, it would be equivalent to *(data + 0), which is equivalent to data…

Thanks. Now I understand why I found pointers difficult. It's the declaration that confused me.
Post reply on HN