Live data from Hacker News

Lesser known tricks, quirks and features of C

blog.joren.ga

181–189 of 189 posts

Re: Lesser known tricks, quirks and features of C

#181

Earlier quoted context omitted.

These days it can be chained with _Atomic to achieve the desired effect. That said, oftentimes you need more serious synchronization mechanisms your library would provide.

_Atomic is indeed the correct qualifier to use for unsynchronized cross-thread access. The volatile qualifier doesn't add anything useful on top of that. Really, the only things volatile should be used for are MMIO, debugging, performance testing, and certain situations with signal handlers or setjmp within a single thread.

From what I gather, _Atomic alone will not ensure that the variable contents are actually loaded every time you load them, and can optimize loops away as a result. You'll often want both.

Re: Lesser known tricks, quirks and features of C

#182

Earlier quoted context omitted.

_Atomic is indeed the correct qualifier to use for unsynchronized cross-thread access. The volatile qualifier doesn't add anything useful on top of that. Really, the only things volatile should be used for are MMIO, debugging, performance testing, and certain situations with signal handlers or setjmp within a single thread.

From what I gather, _Atomic alone will not ensure that the variable contents are actually loaded every time you load them, and can optimize loops away as a result. You'll often want both.

Sure, in principle, compilers can combine certain repeated atomic accesses. But in practice, compilers respect the fact that intervening code takes a nonzero amount of time to run, and always try to load the latest value of the variable. (I am entirely unable to coerce a compiler into combining atomic accesses, even with memory_order_relaxed where it would theoretically be permissible.) Volatile accesses are the same in the sense that the compiler can move the rest of the code around it (and are known to have done so in practice): the only difference is that repeated volatile accesses can't be combined even in theory, and they can't be omitted even if the result is discarded.

What use case do you have in mind where this theoretical possibility would cause issues?

Re: Lesser known tricks, quirks and features of C

#183
post #72

Earlier quoted context omitted.

Why are these not compiler errors by default? Opting in to such important safety features seems like broken design.

How could that really work? printf is a library function, not an intrinsic. A function named printf can do anything your heart desires.

It's a standard library function meaning the compiler can assume that it follows the standard. Specifically for GCC [0]:

> The ISO C90 functions abort, abs, acos, asin, atan2, atan, calloc, ceil, cosh, cos, exit, exp, fabs, floor, fmod, fprintf, fputs, free, frexp, fscanf, isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint, ispunct, isspace, isupper, isxdigit, tolower, toupper, labs, ldexp, log10, log, malloc, memchr, memcmp, memcpy, memset, modf, pow, printf, putchar, puts, realloc, scanf, sinh, sin, snprintf, sprintf, sqrt, sscanf, strcat, strchr, strcmp, strcpy, strcspn, strlen, strncat, strncmp, strncpy, strpbrk, strrchr, strspn, strstr, tanh, tan, vfprintf, vprintf and vsprintf are all recognized as built-in functions unless -fno-builtin is specified (or -fno-builtin-function is specified for an individual function).

Builtin here doesn't mean that GCC won't ever emit calls to library functions, only that it reserves not to and allows itselfs to make assumptions about how the functions work, including diagnosing misuse.

The library functions themselves might also be marked with __attribute__(format(...)) as the sibling comment notes but that is not necessarily required for GCC to check the format strings.

[0] https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html

Re: Lesser known tricks, quirks and features of C

#184
post #38

Very nice collection. My favorite C feature is actually a gcc/clang feature : the __INCLUDE_LEVEL__ predefined macro. It made me code&maintain my C projects exactly twice as fast as before because file count dropped to half : https://github.com/milgra/headerlessc .

Is having two files really that much of a bother? I have my editor set switch between the .c(pp) and the .h with a keyboard shortcut and that seems easier than scrolling between declaration and definition when you want to change something.

Re: Lesser known tricks, quirks and features of C

#185
post #118

Earlier quoted context omitted.

MSVC supports C11 and C17, minus the C99 stuff that was made optional in C11. Anyway given the option, one should always favour C++ over C, if they care about secure code, which while not perfect it is much better than any C compiler will do.

> Anyway given the option, one should always favour C++ over C Eh. I work in embedded, where C reigns supreme. C++ has its own issues in the area, namely that you need to construct your own sub-dialect that removes some features of C++ to make it fit embedded constraints. Commonly, it's C++-but-no-exceptions, sometimes C++-but-no-templates, and others. That said, I'll grant that us embedded developers are effectively…

> sometimes C++-but-no-templates

I can understand exceptions, but what constraints require you to ban templates? If its just code size then it seems a bit arbitrary to ban them completely.

AFAIK most users of C++ do ban some features in their projects so I don't see why that specifically is holding embedded back. Disabling exceptions specifically is something that is not unheard of outside embedded either.

Re: Lesser known tricks, quirks and features of C

#186
post #6

Fun fact about %n: Mazda cars used to have a bug where they used printf(str) instead of printf("%s", str) and their media system would crash if you tried to play the "99% Invisible" podcast in them. All because the "% In" was parsed as a "%n" with some extra modifiers. https://99percentinvisible.org/episode/the-roman-mars-mazda-...

This is one of those annoying little problems that is easily picked up by the vet command (https://pkg.go.dev/cmd/vet) when writing Go code. There are, of course, many linters that do the same thing in C, but it's nice to have an authoritative one built in as part of the official Go toolchain, so everyone's code undergoes the same basic checks.

Re: Lesser known tricks, quirks and features of C

#187
Great read, and lead me to "When VLA in C doesn't smell of rotten eggs" https://blog.joren.ga/vla-usecases and this:

  int n = 3, m = 4;
  int (*matrix_NxM)[n][m] = malloc(sizeof *matrix_NxM); // `n` and `m` are variables with dimensions known at runtime, not compile time
  if (matrix_NxM) {
      // (*matrix_NxM)[i][j] = ...;
      free(matrix_NxM);
  }
Well, that makes much easier a few things I'm doing atm, really glad I read it.

Re: Lesser known tricks, quirks and features of C

#188
post #148

Earlier quoted context omitted.

I found a lot of bugs went away when I switched to STL (Standard Template Library) arrays and ditched managing my own memory. That's C++, I guess it's not available in straight C?

>That's C++, I guess it's not available in straight C? No, because C doesn't have templates. The best you can do for a "vector" in C is macros like above, that also realloc, or write an API around structs for each type.

Too bad. STL deque's are non-contiguous, allow for much bigger arrays. I had an application that used vector, ran out of contiguous memory. deque solved the problem.

Re: Lesser known tricks, quirks and features of C

#189
post #35

Earlier quoted context omitted.

"format not a string literal" is one warning I always upgrade to an error. Dear reader: you should do this, too!

Why are these not compiler errors by default? Opting in to such important safety features seems like broken design.

In principle, they are not enabled by default because a C compiler must be able to compile standard C by default.

One practical reason I can think of is because not everyone compiles their own code.

You must most definitely look for and enable such flags as they become available in your own projects. (eg I was rooting for -Wlifetime but it did not land for various reasons)

But when you compile other people's code, your breaking your local build doesn't help anyone. Best you can do is to submit a bug report, which may or may not be ignored.

Post reply on HN