Live data from Hacker News

Lesser known tricks, quirks and features of C

blog.joren.ga

141–150 of 189 posts

Re: Lesser known tricks, quirks and features of C

#141

Earlier quoted context omitted.

how would you iterate over every possible value of a unsigned int?

The unary complement operator should get you there: unsigned int x = 0; const unsigned int max = ~x; while (x Or, #include const unsigned int max = UINT_MAX;

This is equivalent to

  while (1) {
    calc(x++);
  }
which is an infinite loop, since the expression x is always true

Re: Lesser known tricks, quirks and features of C

#142

Earlier quoted context omitted.

Professional C developers definitely should be using at least designated init and FAM, standard features both added in C99 and currently 24 years old.

Well, it’s either a lesser known trick or it’s something people should be using. In general using lesser known tricks it’s not a good idea for production code. But I understand there are cases where there is no good alternative, so it’s warranted.

My point is that these aren't "lesser known tricks". They're important language features which solve real problems and which anyone writing production C should be at least aware of, if not actively using for the advantages they provide.

Re: Lesser known tricks, quirks and features of C

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

Re: Lesser known tricks, quirks and features of C

#144
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", strerror(errno)); \
        exit(EXIT_FAILURE); \
     }

  #define NEW(ptr) NEW_ARRAY(ptr, 1)

  #endif
With these in place, working with arrays and dynamic memory is safer, less verbose and readability is improved.

Re: Lesser known tricks, quirks and features of C

#145

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…

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?

Re: Lesser known tricks, quirks and features of C

#146

Earlier quoted context omitted.

So in common parlance finite state automata are Turing complete? That definition doesn't make any sense.

Strictly speaking there are essentially no programming languages that are even theoretically Turing-complete because they can only address a bounded amount of memory. For example, in C `sizeof(void*)` must be a well-defined, finite integer. But that definition is not useful in practical use.

There are plenty of Turing complete languages. For example JavaScript is Turing complete.

Re: Lesser known tricks, quirks and features of C

#147
post #134

Earlier quoted context omitted.

So in common parlance finite state automata are Turing complete? That definition doesn't make any sense.

I'd say they're Turing complete (in common parlance) if they can reasonably viewed as a Turing-complete system that's been hobbled with an arbitrary memory limitation. FSAs generally can't be viewed this way as you can't just "add more memory" to an FSA. By way of contrast, consider a pushdown automaton with two stacks. While any physically real implementation of such a device will necessarily have some kind of limit…

>as you can't just "add more memory" to an FSA.

Adding another state to a FSA adds more memory.

There is no difference between a hobbled Turing machine and a FSA. Turing machines aren't a useful concept in the real world and that is okay.

Re: Lesser known tricks, quirks and features of C

#148

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…

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.

Re: Lesser known tricks, quirks and features of C

#149

Never quite understood why compound literals are lvalues, but fine, whatever, I guess, it's so that you can write "&(struct Foo){};" instead of "struct Foo tmp; &tmp;"... which, on a tangential note, reminds me about Go: the proposals to make things like &5 and &true legal in Go were rejected because "the implied semantics would be unclear" even though &structFoo{} is legal and apparently has obvious semantics.

That's extemely useful for invoking a function that takes a pointer to a struct, but you don't want 'taint' the code with a temporary variable that's only needed for the function call:

   func(&(bla_t){ .x = 0, .y = 1 });

Re: Lesser known tricks, quirks and features of C

#150
post #134

Earlier quoted context omitted.

I'd say they're Turing complete (in common parlance) if they can reasonably viewed as a Turing-complete system that's been hobbled with an arbitrary memory limitation. FSAs generally can't be viewed this way as you can't just "add more memory" to an FSA. By way of contrast, consider a pushdown automaton with two stacks. While any physically real implementation of such a device will necessarily have some kind of limit…

>as you can't just "add more memory" to an FSA. Adding another state to a FSA adds more memory. There is no difference between a hobbled Turing machine and a FSA. Turing machines aren't a useful concept in the real world and that is okay.

>Adding another state to a FSA adds more memory.

Yes, but it also changes the state transition logic. You can't just 'add 100 more states' to an FSA in the same way that you can 'add 100 more stack slots' to a bounded pushdown automaton.

As I said previously, these are somewhat fuzzy distinctions, and I'm not saying that they're easy to make mathematically precise. They do however seem clear enough in most cases of practical interest. There are many real-world computing systems that would be Turing-complete if they had unbounded memory. There are others that are not Turing-complete for more fundamental reasons than memory limitations. Again, I acknowledge that 'more fundamental' is not a mathematically precise concept.

Post reply on HN