1 of 25

Hello for the secondthirdfourth time, Reddit.

This was a 10-minute lightning talk. It is a presentation, not a book. I spoke when presenting it. Not everything that was said is on these slides, as that would have made for a boring talk. Yes, there are counter examples to some of the things mentioned, and they were discussed when it was presented. And it's meant to be amusing, not dry. Get a grip on yourselves.

Lots of love, rjek.

P.S. If you want to share this with somebody you know, just give them the URL you received. Do not click "share", as I get an email every time asking to grant permission. These now just get binned automatically so I don't feel the need to smite the universe.

P.P.S. Yes, this is in Comic Sans just to troll you.

2 of 25

Some dark corners of C

-std=c99 -pedantic -Wall -Warn-me-harder

Stolen from Rob Kendrick <rjek+dark corners@rjek.com>

Rob Kendrick <rob.kendrick@codethink.co.uk>

3 of 25

Dark corner of C

Here it is!

4 of 25

Shadowy escape

int x = 42;�int func() {� int x = 3840;� {� return x;� }�}�

int x = 42;�int func() {� int x = 3840;� {� extern int x;� return x;� }�}

Returns 3840

Returns 42

5 of 25

Bizarre keyword reuse

void foo(int x[static 10]);

void foo(char x[static 1]);

Passed array must be at least 10 entries.�foo.c:8:2: warning: array argument is too small; contains 5 elements, callee requires at least 10 [-Warray-bounds]

Free compile-time non-NULL check!�foo.c:8:2: warning: null passed to a callee which requires a non-null argument [-Wnonnull]

6 of 25

Warning: Don't breathe this

int x = 'FOO!';

Yes, that's right, it makes demons fly out of your nose!

(On my system, 1,179,602,721.)

If you do this, I will find you.

Yes, single quotes.

7 of 25

[ ] is just + in disguise

assert(spong[x] == x[spong]);

assert(spong[2] == 2[spong]);

d = "0123456789abcdef"[n];

d = n["0123456789abcdef"];

8 of 25

Pointer aliasing

void foo1(int *x, int *y, int *z) {� *x += *z;� *y += *z;�}

movl (%rdx), %eax�addl %eax, (%rdi)�movl (%rdx), %eax�addl %eax, (%rsi)�ret�

Compiler doesn't know that *z won't also be *x, so loads it twice :(

9 of 25

Pointer aliasing: Fixed?

void foo2(int *x, int *y, int *z) {

int w = *z;� *x += w;� *y += w;�}

movl (%rdx), %eax�addl %eax, (%rdi)�addl %eax, (%rsi)�ret��

Only one load, at the cost of beauty.

10 of 25

Pointer aliasing: Fixed!

void foo3(int *x, int *y,

int * restrict z) {� *x += *z;� *y += *z;�}

movl (%rdx), %eax�addl %eax, (%rdi)�addl %eax, (%rsi)�ret��

'restrict' means we promise not to mess about.

11 of 25

Counting up ...

int fact1(int n) {� int i, fact = 1;� for (i = 1; i <= n;

i++)� fact *= i;� return fact;�}

fact1:�movl $1, %eax�testl %edi, %edi�jle .exit�xorl %ecx, %ecx�.loop:�incl %ecx�imull %ecx, %eax�cmpl %ecx, %edi�jne .loop�.exit �ret�

12 of 25

... vs counting down

int fact2(int n) {� int fact = 1;

if (n == 0)

return fact;� do� fact *= n;� while (--n != 0);

return fact;�}�

fact2:�testl %edi, %edi�movl $1, %eax�je .exit�.loop:�imull %edi, %eax�subl $1, %edi�jne .loop�.exit: �ret

13 of 25

const confusion

const int foo = 10;

const int *foop = &foo;

"Constant" integer foo with value 10.

And a "constant" pointer to it?

int i = 20;

foop = &i;

Oops. const binds left. But if there's nothing to its left, it binds to the right.

14 of 25

Munchy munchy.

z = y+++x;

The C specification says that when there is such an ambiguity, munch as much as possible. (The "greedy lexer rule".)

z = y++ + x;

15 of 25

Munchy munchy. Again.

z = y+++++x;

Alas, not

z = y++ + ++x;

But

z = y++ ++ +x;

Parser go boom.

16 of 25

C keywords

auto break case char const continue default do

double else enum extern float for goto if int

long register restrict return short signed sizeof static struct switch typedef union unsigned void volatile while

Wait, what? auto is a bizarreness left over from B. The only place it's valid, it's also the default. And that's to say a variable should be automatically managed, ie, placed on the stack. static is its antonym. Ish.

17 of 25

Smallest C program

What's the smallest C program that will compile and link?

int main;

(Don't run this.)

main;

Alas it produces a warning. So we can do this:

18 of 25

Global variables are filthy

foo1.c:

int x;

foo2.c:

int x;

int main() { printf("%d\n", x); }

$ gcc -o foo foo1.c foo2.c

$ echo $?

0

19 of 25

Global variables are filthy

foo1.c:

int x = 42;

foo2.c:

int x;

int main() { printf("%d\n", x); }

$ gcc -o foo foo1.c foo2.c

$ echo $?

0

20 of 25

Global variables are filthy

foo1.c:

int x = 0;

foo2.c:

int x = 0;

int main() { printf("%d\n", x); }

$ gcc -o foo foo1.c foo2.c

/tmp/ccx4aT9m.o:(.bss+0x0): multiple definition of `x'

21 of 25

// comments are evil

int foo() {� int a = 10, b = 2;� return a //*� //*/ b� ;�}

C89: 5

C++: 10

C99: 10

22 of 25

Portable lossless floats

printf("%a\n", 1.2345);

0x1.3c083126e978dp+0

printf("%f\n",atof("0x1.3c083126e978dp+0"));�

1.234500

23 of 25

Ruin somebody's day

What would you sneak into somebody's headers to drive them mad?

#define struct union

#define else

24 of 25

Recommended reads

Sadly very few modern books on the subject of C :(

25 of 25

Thanks for ideas/input...

David Thomas

Daniel Silverstone

Clive Jones

Peter Van Der Linden

Erlend Hamberg�