switch(count % 8) {
case 0: do{ putchar('0' + (int)j);
case 7: putchar('0' + (int)j);
case 6: putchar('0' + (int)j); /* Unrolled
case 5: putchar('0' + (int)j); * for greater
case 4: putchar('0' + (int)j); * speed.
case 3: putchar('0' + (int)j); */
case 2: putchar('0' + (int)j);
case 1: putchar('0' + (int)j);
} while(--j > 0);
Without syntax highlighting, a passing glance may not recognize cases 3 through 5 are commented out.And even then it is a matter of experience. It looks odd to me to have multiline comments not in its own 'paragraph' of the code, so draws the eye right away. Perhaps this would foil some programmers, but not more than once, I'd have thought. In my experience, run-on compound statements are much more common and hard to intuitively spot:
if (foo)
bar();
sun();
Duff's device is difficult to understand from first principles, but even that is a bad example of unmaintainable code because a) it looks like nothing except Duff's device, you only need to see the pattern once or twice and you'd recognise it, and at least know 'it's that weird pattern for unrolling loops', and b) it is a performance optimisation that only belongs in code that is profiled and needs to go that fast. As such it should be well commented to avoid regressions by well meaning refactor-zealots. Inline assembly or heavy intrinsics are more difficult to read than regular C too, so you only use them when you need to. In my experience manual loop unrolling is very rarely needed.Although it should be noted that the original person to use Duff's device did admit that he tried everything else to optimize it and only that worked, and he never advocated that people should use it as a general optimization technique.
Note that with gcc, you can reach the same results by using the 'indirect goto' that is both more powerful, and more dangerous! void * lab; lab = &my_label; goto *lab; my_label: ...
I liked a lot how you switch on count and loop on j. If gcc didn't comply, I would never notice it.
This is actually a very useful technique that I use all the time. It allows you to make sure that a function and any function pointers that point to it always have matching types (since you only have to change the prototype in one place - the typedef).
In C you can cast a pointer, okay anything really, to a function pointer and then call it.
int foo(int a, int b){return a+b; }
void *vptr = foo;
int (*yolo)(int a) = vptr;
int c = yolo(10); // Cthulhu come
This sort of thing can happen when you pass a function pointer into some sort of callback mechanism+. When you get it back you have to cast it to the right type and then call it. So there is a disconnect between the cast and the function definition, unless you tie both together with a typedef.+ Often helpful for an api that takes a callback to also record, who the caller was and some arbitrary bit of data. The arbitary bit of data might be a function pointer.
Later, when I want to call the original function, I assign to a properly typed variable to the value of the void
original_function member. The compiler has no way to know if that void * is actually FILE (fopen )(char , char ) or if it's int(open )(char , int, ...).When everything can be properly typed, I only ever get warnings about assigning the wrong function types to the wrong function pointer variables.
If you try to cast a pointer into your function type, you'll get a runtime error, not a compile time one.
struct items_with_header { int header_field1; unsigned int length; double array[]; };
Then allocate enough memory and use the struct to access it.
Used it once in a hash-table implementation.
typename identifier[];
means three different things, depending on where it appears: As a function argument, it is a pointer that will be accessed like an array. As a variable with automatic storage duration, it is an array whose size will be determined by the right-hand-side of an assignment from a braced initializer list. In the middle of a struct definition, it's illegal. And at the end of a struct definition, it is a flexible array member.
class Bar {};
class Foo {
public:
Foo(const Bar &c) { }
void method() { }
};
int main() {
Foo foo(Bar());
foo.method();
return 0;
}
"foo.method();" doesn't compile because: error: request for member ‘method’ in ‘foo’, which is of non-class type ‘Foo(Bar (*)())’
That's right: "foo" is a declared function that returns instance of Foo and takes one argument - a function that returns instance of Bar :) But when you add additional parentheses in a line above: Foo foo((Bar()));
then "foo" is an instance of Foo created by passing a new instance of Bar to its constructor, which is more like what you'd expect by reading the code, and the code compiles. Fun!https://github.com/sepeth/python-skiplist/commit/00ae7f94246...
Redis's skiplist is also using the same feature:
https://github.com/antirez/redis/blob/unstable/src/server.h#...
"The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined"
There is no guarantee on the order of the bits inside a bitfield. The compiler may also introduce padding, e.g. for alignment purposes. This makes bitfields unusable for unpacking binary data.
Unfortunately, you're stuck with shifting and masking to replicate the same effect.
The problem was that some bits in that register would be cleared automatically each time, so even if you wrote 0 it would read back as 1 the next time. Some other bit would always trigger an action if you wrote to it regardless if you wrote the same value as it had before, this was called the send_bit and when you wrote 0 it sent some stuff onto the network cable. So code that looked perfectly fine like this:
register.bitsa = 0x2;
register.bitsb = 0x1;
register.send_bit = 0.
Actually sent 3 packets instead of 1 because the compiler translated each write of a bitfield member to a write of the whole register, some other bits in bitsa could get corrupted by the bitsb-write since they didn't read back as they were written. I assume the cpu had a minimum addressable unit of 8 bits so the compiler had to translate each line into something like register = (register | setbits) & clearbits; which requires reading the previous value each time just to write a single bit, this is very easy to overlook when you just see the three lines of code being written in a neat sequence.union { int x; float y; } b; b.y = 10e5; printf("%x\n", b.x);
That behavior is legal and well-defined behavior (up to the implementation-defined nature of representations) under C99 and C11, but not under C89 and earlier. Unfortunately, although it was made legal in C99, C99 did retain the program as an example in its (non-normative) list of undefined behaviors, which doesn't help clear up its legality.
Its status under C++11 and C++14 is much more debatable. I recall (I may have bad memory) that an early draft of C++0x had incorporated new C99 text on unions, which would have made it legal, but the wording of unions changed dramatically when unrestricted unions were introduced, which means that assessing its present legality relies very heavily on how you extend initialization to types like int and float.
http://stackoverflow.com/questions/11639947/is-type-punning-...
size_t typedef length;
struct {
int x, y;
} typedef foo, *pfoo; #define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
_-_-_-_
_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_
_-_-_-_
} *(const char * + char *) The type of int i is converted to 'char *' and multiplied by sizeof(char)
I am pretty certain this explanation does not make any sense: what is really happening here is that the int, for purposes of the addition, is measuring units sizeof the object being pointed to; there is no meaning I know of to adding two pointers. /* This works because "Hello"[5] == 5["Hello"].*/
At this point, you could really just say the following: /* This works because a[b] == *(a + b), and addition is commutative. */Umm, that's really not that restrictive. Use `clang -Weverything -std=c11 main.c` if you want strict warnings.