Live data from Hacker News

Lesser known tricks, quirks and features of C

blog.joren.ga

171–180 of 189 posts

Re: Lesser known tricks, quirks and features of C

#171
post #118

Compound Literals in C are great. They're no surprise to anyone coming from more sophisticated languages, but I've never seen them used in the C codebases I've worked on. What with C also allowing structures as return values, another rarely-used feature, they're really useful for allowing a richer API than the historical `int foo(...)` that so many people are used to seeing. C has so much legacy that it's really hard…

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 "traumatized" and have difficulty accepting new approaches because we're too focused on certain paradigms that are no longer relevant (See my previous about returning structures, which has encountered responses like "but then it might do an extra memcpy()!!11")

Re: Lesser known tricks, quirks and features of C

#172

There are three macros which I find indispensable and which I use in all my C projects, namely LEN , NEW and NEW_ARRAY . I keep them in a file named Util.h: #ifndef UTIL_H #define UTIL_H #include #include #include #include #define LEN(arr) (sizeof (arr) / sizeof (arr)[0]) #define NEW_ARRAY(ptr, n) \ (ptr) = malloc((n) * sizeof (ptr)[0]); \ if ((ptr) == NULL) { \ fprintf(stderr, "Memory allocation failed: %s\n", strer…

With gcc you can use this to get the elements of an array.

   // will barf if fed a pointer
   #define sizeof_array(arr) \
       (sizeof(arr) / sizeof((arr)[0]) \
       + sizeof(typeof(int[1 - 2 * \
       !!__builtin_types_compatible_p(typeof(arr), \
       typeof(&arr[0]))])) * 0)

Re: Lesser known tricks, quirks and features of C

#173
post #132

I'm currently trying to make a programming language that translates to C. I've started with a pseudo BNF parser. I started reading the C BNF and I have to admit that I was not prepared at all. It's not as easy as it sounds. I cannot imagine how difficult it must be to maintain a modern C++ compiler.

Yeah, good luck hahaha There is a reason why modern languages use keywords like "func", "def", "fn", "var", "let" to discern between different types of declarations, for example. I dont think many languages are LL(k) (please correct me if im wrong), but C is as far away from that as it gets, for small k.

I've thought it would be nice to add func to the language. Even if it's just sugar it would help. Type inference + allowing functions to return an anonymous struct or a tuple would be super.

Re: Lesser known tricks, quirks and features of C

#174
post #118

Compound Literals in C are great. They're no surprise to anyone coming from more sophisticated languages, but I've never seen them used in the C codebases I've worked on. What with C also allowing structures as return values, another rarely-used feature, they're really useful for allowing a richer API than the historical `int foo(...)` that so many people are used to seeing. C has so much legacy that it's really hard…

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.

> MSVC supports C11 and C17, minus the C99 stuff that was made optional in C11.

Sure they do now. They were particularly slow at implementing a bunch of C99 stuff, some of it landing only in VS 2019

https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-la...

MSVC has long lagged in C support because they focused on that subset of C standards that were required for C++.

https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...

Re: Lesser known tricks, quirks and features of C

#175
post #168

Earlier quoted context omitted.

It is specified by POSIX, but not by ISO C (or C++). So most Unix(-like) systems support it. But the printf in Microsoft's C runtime doesn't. However, Microsoft does define an alternative printf function which does, printf_p, so `#define printf printf_p` will get past that. I think the real reason you rarely see it, is it is only used with internationalisation–the idea being if you translate the format string, the tr…

printf_p is pretty neat, thanks for the pointer. But I would bet that you will still find at least one %d gets turned into a %s. I like printf format strings, but as a way of handling localizable strings I don't think they are the best.

You are 100% correct. printf, even with the argument numbering feature, is insufficient for high quality internationalisation.

A good example of this is pluralisation. We've all done things like:

    printf("%d file(s) copied\n", count);
which is acceptable but kind of ugly. Some people want to make it nicer:

    printf("%d file%s copied\n", count, count != 1 ? "s" : "");
Which is fine for English, but doesn't work at all for other languages. The problem is not just that the plural ending is something other than `s` – if it was just that, it wouldn't be too hard. The problem is that the `count != 1` bit only works for English. For example, while 0 is plural in English, in French it is singular. Many other languages are much more complex. The GNU gettext manual has a chapter which goes into this in great detail – https://www.gnu.org/software/gettext/manual/html_node/Plural...

printf() has zero hope of coping with this complexity. gettext provides a special function to handle this, ngettext(), which is passed the number as a separate argument, so it can select which plural form to use. And then the translated message files contain a header defining how many plural forms that language has, and the rules to choose which one to use. And for some languages it is crazy complex. Arabic is the most extreme, for which the manual gives this plural rule:

    Plural-Forms: nplurals=6; \
        plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100=11 ? 4 : 5;

Re: Lesser known tricks, quirks and features of C

#176

I am not able to understand how int (*ap3)[900000] = malloc(sizeof *ap3); is nicer than int *a = malloc(900000 * sizeof *a); Notice that, in the former case, the array elements must be accessed as (*ap3)[i] whereas in the latter case the usual method a[i] is fine.

You don't use this technique to define a new array, but to get a pointer to an array you already have.

The goal is to have a pointer to the array, and not a pointer to the first element of the array.

Whether this is "nicer" or not, and whether this is what you need in your application, are out of the scope of the fine article.

Re: Lesser known tricks, quirks and features of C

#178
post #51
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-...

Also iPhones had a RCE uaing a WiFi Name that contained %s https://thehackernews.com/2021/07/turns-out-that-low-risk-io...

%@.

Re: Lesser known tricks, quirks and features of C

#179

Earlier quoted context omitted.

I think register is closer to const, as in: it's a hint to the programmer not the compiler. So if you want to make absolutely sure that a variable can always be in a register then you should consider adding the register specifier to stop other programmers from taking the address of that variable.

Taking the address of a variable does not prevent the compiler from putting it in a register. Indeed, it can be convenient to have small utility functions which are always inlined, which take pointers to their results; this should not and does not prevent those results from staying in registers.

Correct, but preventing people from taking the address of things actually makes a difference for certain constructs in the standard (fore example, when it comes to trap representations).

Re: Lesser known tricks, quirks and features of C

#180

I remember once upon a time I thought C was fairly simple, so I decided to write a program to generate ASTs from C programs. I was very wrong and it was kind of a nightmare. There are so many weird little quirks or lesser-used features that I never saw in the wild even in large production codebases; I feel like you really don't _need_ a lot of these features. I can't imagine doing proper compiler work, especially for…

[deleted]
Post reply on HN