#include <stdio.h>struct X { int

Deep C (and C++) by
Olve Maudal and Jon Jagger http://www.noaanews.noaa.gov/stories2005/images/rov-hercules-titanic.jpgProgramming is hard. Programming correct C and C++ is particularly hard. Indeed, both in Cand certainly in C++, it is uncommon to see a screenful containing only well deﬁned andconforming code. Why do professional programmers write code like this? Because mostprogrammers do not have a deep understanding of the language they are using. While theysometimes know that certain things are undeﬁned or unspeciﬁed, they often do not know whyit is so. In these slides we will study small code snippets in C and C++, and use them to discussthe fundamental building blocks, limitations and underlying design philosophies of thesewonderful but dangerous programming languages. October 2011

Suppose you are about to
interview a candidate for a position asC programmer for various embedded platforms. As part of theinterview you might want to check whether the candidate has adeep understanding of the programming language or not... hereis a great code snippet to get the conversation started:

Suppose you are about to
interview a candidate for a position asC programmer for various embedded platforms. As part of theinterview you might want to check whether the candidate has adeep understanding of the programming language or not... hereis a great code snippet to get the conversation started: int main() { int a = 42; printf(“%dn”, a); }

Suppose you are about to
interview a candidate for a position asC programmer for various embedded platforms. As part of theinterview you might want to check whether the candidate has adeep understanding of the programming language or not... hereis a great code snippet to get the conversation started: int main() { int a = 42; printf(“%dn”, a); } What will happen if you try to compile, link and run this program?

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); } One candidate might say:

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); } You must #include <stdio.h>, add One candidate might say: a return 0 and then it will compile and link. When executed it will print the value 42 on the screen.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); } You must #include <stdio.h>, add One candidate might say: a return 0 and then it will compile and link. When executed it will print the value 42 on the screen. and there is nothing wrong with that answer...

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }But another candidate might use this as an opportunity to startdemonstrating a deeper understanding. She might say things like:

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }But another candidate might use this as an opportunity to startdemonstrating a deeper understanding. She might say things like: You probably want to #include <stdio.h> which has an explicit declaration of printf(). The program will compile, link and run, and it will write the number 42 followed by a newline to the standard output stream.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and then she elaboratesa bit by saying:

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and then she elaborates A C++ compiler will refuse to compile this code as the language requires explicit declaration of all functions.a bit by saying:

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and then she elaborates A C++ compiler will refuse to compile this code as the language requires explicit declaration of all functions.a bit by saying: However a proper C compiler will create an implicit declaration for the function printf(), compile this code into an object ﬁle.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and then she elaborates A C++ compiler will refuse to compile this code as the language requires explicit declaration of all functions.a bit by saying: However a proper C compiler will create an implicit declaration for the function printf(), compile this code into an object ﬁle. And when linked with a standard library, it will ﬁnd a deﬁnition of printf()that accidentally will match the implicit declaration.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and then she elaborates A C++ compiler will refuse to compile this code as the language requires explicit declaration of all functions.a bit by saying: However a proper C compiler will create an implicit declaration for the function printf(), compile this code into an object ﬁle. And when linked with a standard library, it will ﬁnd a deﬁnition of printf()that accidentally will match the implicit declaration. So the program above will actually compile, link and run.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and then she elaborates A C++ compiler will refuse to compile this code as the language requires explicit declaration of all functions.a bit by saying: However a proper C compiler will create an implicit declaration for the function printf(), compile this code into an object ﬁle. And when linked with a standard library, it will ﬁnd a deﬁnition of printf()that accidentally will match the implicit declaration. So the program above will actually compile, link and run. You might get a warning though.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and while she is on the roll, she might continue with:

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and while she is on the roll, she might continue with: If this is C99, the exit value is deﬁned to indicate success to the runtime environment, just like in C++98, but for older versions of C, like ANSI C and K&R, the exit value from this program will be some undeﬁned garbage value.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and while she is on the roll, she might continue with: If this is C99, the exit value is deﬁned to indicate success to the runtime environment, just like in C++98, but for older versions of C, like ANSI C and K&R, the exit value from this program will be some undeﬁned garbage value. But since return values are often passed in a register I would not be surprised if the garbage value happens to be 3... since printf() will return 3, the number of characters written to standard out.

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and while she is on the roll, she might continue with:

What will happen if you
try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }and while she is on the roll, she might continue with: And talking about C standards... if you want to show that you care about C programming, you should use int main(void) as your entry point - since the standard says so. Using void to indicate no parameters is essential for declarations in C, eg a declaration ‘int f();’, says there is a function f that takes any number of arguments. While you probably meant to say ‘int f(void);’. Being explicit by using void also for function deﬁnitions does not hurt.

What will happen if you
try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }

What will happen if you
try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }and to really show off... Also, if you allow me to be a bit pedantic... the program is not really compliant, as the standard says that the source code must end with a newline.

What will happen if you
try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }

What will happen if you
try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }

What will happen if you
try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); } ah, remember to include an explicit declaration of printf() as well

What will happen if you
try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }

What will happen if you
try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); } now, this is a darn cute little C program! Isn’t it?

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }and here is what I get when compiling, linking and running theabove program on my machine:

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }and here is what I get when compiling, linking and running theabove program on my machine: $ cc -std=c89 -c foo.c

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }and here is what I get when compiling, linking and running theabove program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }and here is what I get when compiling, linking and running theabove program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }and here is what I get when compiling, linking and running theabove program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out 42

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }and here is what I get when compiling, linking and running theabove program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out 42 $ echo $?

What will happen if you
try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }and here is what I get when compiling, linking and running theabove program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out 42 $ echo $? 3

Now suppose they are not
really candidates. Perhaps they are stereotypes for engineers working in your organization?Would it be useful if most of your colleagues have a deepunderstanding of the programming language they are using?

#include <stdio.h> eh, is it
undeﬁned? do you get garbage values?void foo(void) No, you get 1, then 2, then 3{ static int a; ++a; ok, I see... why? printf("%dn", a);} because static variables are set to 0int main(void){ foo(); foo(); foo();}

#include <stdio.h> eh, is it
undeﬁned? do you get garbage values?void foo(void) No, you get 1, then 2, then 3{ static int a; ++a; ok, I see... why? printf("%dn", a);} because static variables are set to 0int main(void){ foo(); foo(); foo();}

#include <stdio.h> eh, is it
undeﬁned? do you get garbage values?void foo(void) No, you get 1, then 2, then 3{ static int a; ++a; ok, I see... why? printf("%dn", a);} because static variables are set to 0int main(void){ foo(); foo(); the standard says that static variables are initialized foo(); to 0, so this should print 1, then 2, then 3}

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ int a; ++a; printf("%dn", a);}int main(void){ foo(); foo(); foo();}

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ Because you said they where initialized to 0 int a; ++a; printf("%dn", a);}int main(void){ foo(); foo(); foo();}

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ Because you said they where initialized to 0 int a; ++a; But this is not a static variable printf("%dn", a);}int main(void){ foo(); foo(); foo();}

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ Because you said they where initialized to 0 int a; ++a; But this is not a static variable printf("%dn", a);} ah, then you get three garbage valuesint main(void){ foo(); foo(); foo();}

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ Because you said they where initialized to 0 int a; ++a; But this is not a static variable printf("%dn", a);} ah, then you get three garbage valuesint main(void){ foo(); foo(); foo();}

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ Because you said they where initialized to 0 int a; ++a; But this is not a static variable printf("%dn", a);} ah, then you get three garbage valuesint main(void) the value of a will be undeﬁnded, so in theory you{ get three garbage values. In practice however, since foo(); auto variables are often allocated on an execution foo(); stack, a might get the same memory location each foo(); time and you might get three consecutive values... if} you compile without optimization.

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ Because you said they where initialized to 0 int a; ++a; But this is not a static variable printf("%dn", a);} ah, then you get three garbage valuesint main(void) the value of a will be undeﬁnded, so in theory you{ get three garbage values. In practice however, since foo(); auto variables are often allocated on an execution foo(); stack, a might get the same memory location each foo(); time and you might get three consecutive values... if} you compile without optimization. on my machine I actually get, 1, then 2, then 3

Now you get 1, then
1, then 1#include <stdio.h> Ehm, why do you think that will happen?void foo(void){ Because you said they where initialized to 0 int a; ++a; But this is not a static variable printf("%dn", a);} ah, then you get three garbage valuesint main(void) the value of a will be undeﬁnded, so in theory you{ get three garbage values. In practice however, since foo(); auto variables are often allocated on an execution foo(); stack, a might get the same memory location each foo(); time and you might get three consecutive values... if} you compile without optimization. on my machine I actually get, 1, then 2, then 3 I am not surprised... if you compile in debug mode the runtime might try to be helpful and memset your stack memory to 0

#include <stdio.h> Why do you
think static variables are set to 0, while auto variables are not initialized?void foo(void){ int a; eh? ++a; printf("%dn", a);} The cost of setting auto variables to 0 would increase the cost of function calls. C has a veryint main(void) strong focus on execution speed.{ foo(); foo(); foo();}

#include <stdio.h> Why do you
think static variables are set to 0, while auto variables are not initialized?void foo(void){ int a; eh? ++a; printf("%dn", a);} The cost of setting auto variables to 0 would increase the cost of function calls. C has a veryint main(void) strong focus on execution speed.{ foo(); foo(); Memsetting the global data segment to 0 foo(); however, is a one time cost that happens at} start up, and that might be the reason why it is so in C.

#include <stdio.h> Why do you
think static variables are set to 0, while auto variables are not initialized?void foo(void){ int a; eh? ++a; printf("%dn", a);} The cost of setting auto variables to 0 would increase the cost of function calls. C has a veryint main(void) strong focus on execution speed.{ foo(); foo(); Memsetting the global data segment to 0 foo(); however, is a one time cost that happens at} start up, and that might be the reason why it is so in C. And to be precise, in C++ however, static variables are not set to 0, they are set to their default values... which for native types means 0.

garbage, garbage, garbage#include <stdio.h> why
do you think that?int a; oh, is it still initialized to 0?void foo(void){ yes ++a; printf("%dn", a); maybe it will print 1, 2, 3?} yesint main(void){ do you know the difference between this code foo(); snippet and the previous code snippet (with static foo(); before int a)? foo();}

garbage, garbage, garbage#include <stdio.h> why
do you think that?int a; oh, is it still initialized to 0?void foo(void){ yes ++a; printf("%dn", a); maybe it will print 1, 2, 3?} yesint main(void){ do you know the difference between this code foo(); snippet and the previous code snippet (with static foo(); before int a)? foo();} not really, or wait a minute, it has do with private variables and public variables.

garbage, garbage, garbage#include <stdio.h> why
do you think that?int a; oh, is it still initialized to 0?void foo(void){ yes ++a; printf("%dn", a); maybe it will print 1, 2, 3?} yesint main(void){ do you know the difference between this code foo(); snippet and the previous code snippet (with static foo(); before int a)? foo();} not really, or wait a minute, it has do with private variables and public variables. yeah, something like that...

it will print 1, 2,
3, the variable is still statically#include <stdio.h> allocated and it will be set to 0int a;void foo(void){ ++a; printf("%dn", a);}int main(void){ foo(); foo(); foo();}

it will print 1, 2,
3, the variable is still statically#include <stdio.h> allocated and it will be set to 0int a;void foo(void) do you know the difference between this{ code snippet and the previous code ++a; snippet (with static before int a)? printf("%dn", a);}int main(void){ foo(); foo(); foo();}

it will print 1, 2,
3, the variable is still statically#include <stdio.h> allocated and it will be set to 0int a;void foo(void) do you know the difference between this{ code snippet and the previous code ++a; snippet (with static before int a)? printf("%dn", a);}int main(void){ sure, it has to do with linker visibility. Here the variable is foo(); accessible from other compilation units, ie the linker can let foo(); another object ﬁle access this variable. If you add static in foo(); front, then the variable is local to this compilation unit and} not visible through the linker.

I am now going to
show you something cool!#include <stdio.h> $ cc foo.c && ./a.out 42void foo(void){ Can you explain this behaviour? int a; printf("%dn", a);} eh?void bar(void) Perhaps this compiler has a pool of{ named variables that it reuses. Eg int a = 42; variable a was used and released in} bar(), then when foo() needs an integer names a it will get theint main(void) variable will get the same memory{ location. If you rename the variable bar(); in bar() to, say b, then I don’t think foo(); you will get 42.}

I am now going to
show you something cool!#include <stdio.h> $ cc foo.c && ./a.out 42void foo(void){ Can you explain this behaviour? int a; printf("%dn", a);} eh?void bar(void) Perhaps this compiler has a pool of{ named variables that it reuses. Eg int a = 42; variable a was used and released in} bar(), then when foo() needs an integer names a it will get theint main(void) variable will get the same memory{ location. If you rename the variable bar(); in bar() to, say b, then I don’t think foo(); you will get 42.} Yeah, sure...

I am now going to
show you something cool!#include <stdio.h> $ cc foo.c && ./a.out 42void foo(void){ Nice! I love it! int a; printf("%dn", a); You now want me to explain about} execution stack or activation frames?void bar(void) I guess you have already demonstrated{ that you understand it. But what do you int a = 42; think might happen if we optimize this} code or use another compiler?int main(void){ bar(); foo();}

I am now going to
show you something cool!#include <stdio.h> $ cc foo.c && ./a.out 42void foo(void){ Nice! I love it! int a; printf("%dn", a); You now want me to explain about} execution stack or activation frames?void bar(void) I guess you have already demonstrated{ that you understand it. But what do you int a = 42; think might happen if we optimize this} code or use another compiler?int main(void){ A lot of things might happen when the optimizer kicks in. In bar(); this case I would guess that the call to bar() can be skipped as foo(); it does not have any side effects. Also, I would not be surprised} if the foo() is inlined in main(), ie no function call. (But since foo () has linker visibility the object code for the function must still be created just in case another object ﬁle wants to link with the function). Anyway, I suspect the value printed will be something else if you optimize the code.

#include <stdio.h> I would never
write code like that.void foo(void) That’s nice to hear!{ int a = 41; a = a++; But I think the answer is 42 printf("%dn", a);}int main(void){ foo();}

#include <stdio.h> I would never
write code like that.void foo(void) That’s nice to hear!{ int a = 41; a = a++; But I think the answer is 42 printf("%dn", a);} Why do you think that?int main(void){ foo();}

#include <stdio.h> I would never
write code like that.void foo(void) That’s nice to hear!{ int a = 41; a = a++; But I think the answer is 42 printf("%dn", a);} Why do you think that?int main(void) Because what else can it be?{ foo();}

#include <stdio.h> I would never
write code like that.void foo(void) That’s nice to hear!{ int a = 41; a = a++; But I think the answer is 42 printf("%dn", a);} Why do you think that?int main(void) Because what else can it be?{ foo(); Indeed, 42 is exactly what I get when I} run this on my machine

#include <stdio.h> I would never
write code like that.void foo(void) That’s nice to hear!{ int a = 41; a = a++; But I think the answer is 42 printf("%dn", a);} Why do you think that?int main(void) Because what else can it be?{ foo(); Indeed, 42 is exactly what I get when I} run this on my machine hey, you see!

#include <stdio.h> I would never
write code like that.void foo(void) That’s nice to hear!{ int a = 41; a = a++; But I think the answer is 42 printf("%dn", a);} Why do you think that?int main(void) Because what else can it be?{ foo(); Indeed, 42 is exactly what I get when I} run this on my machine hey, you see! But the code is actually undeﬁned.

#include <stdio.h> I would never
write code like that.void foo(void) That’s nice to hear!{ int a = 41; a = a++; But I think the answer is 42 printf("%dn", a);} Why do you think that?int main(void) Because what else can it be?{ foo(); Indeed, 42 is exactly what I get when I} run this on my machine hey, you see! But the code is actually undeﬁned. Yeah, I told you - I never write code like that

#include <stdio.h> a gets an
undeﬁned valuevoid foo(void) I don’t get a warning when compiling it,{ and I do get 42 int a = 41; a = a++; printf("%dn", a);}int main(void){ foo();}

#include <stdio.h> a gets an
undeﬁned valuevoid foo(void) I don’t get a warning when compiling it,{ and I do get 42 int a = 41; a = a++; printf("%dn", a); Then you must increase the warning level,} the value of a is certainly undeﬁned after the assignment and increment because youint main(void) violate one of the fundamental rules in C{ (and C++). The rules for sequencing says foo(); that you can only update a variable once} between sequence points. Here you try to update it two times, and this causes a to become undeﬁned.

#include <stdio.h> a gets an
undeﬁned valuevoid foo(void) I don’t get a warning when compiling it,{ and I do get 42 int a = 41; a = a++; printf("%dn", a); Then you must increase the warning level,} the value of a is certainly undeﬁned after the assignment and increment because youint main(void) violate one of the fundamental rules in C{ (and C++). The rules for sequencing says foo(); that you can only update a variable once} between sequence points. Here you try to update it two times, and this causes a to become undeﬁned. So you say a can be whatever? But I do get 42

#include <stdio.h> a gets an
undeﬁned valuevoid foo(void) I don’t get a warning when compiling it,{ and I do get 42 int a = 41; a = a++; printf("%dn", a); Then you must increase the warning level,} the value of a is certainly undeﬁned after the assignment and increment because youint main(void) violate one of the fundamental rules in C{ (and C++). The rules for sequencing says foo(); that you can only update a variable once} between sequence points. Here you try to update it two times, and this causes a to become undeﬁned. So you say a can be whatever? But I do get 42Indeed! a can be 42, 41, 43, 0, 1099, or whatever... I am not surprised that your machine givesyou 42... what else can it be here? Or perhaps the compiler choose 42 whenever a value isundeﬁned ;-)

#include <stdio.h> int b(void) {
puts(“3”); return 3; } int c(void) { puts(“4”); return 4; } int main(void) { int a = b() + c(); printf(“%dn”, a); }Easy, it prints 3, 4 and then 7 Actually, this could also be 4, 3 and then 7 Huh? Is the evaluation order undeﬁned? It is not really undeﬁned, it is unspeciﬁed

#include <stdio.h> int b(void) {
puts(“3”); return 3; } int c(void) { puts(“4”); return 4; } int main(void) { int a = b() + c(); printf(“%dn”, a); }Easy, it prints 3, 4 and then 7 Actually, this could also be 4, 3 and then 7 Huh? Is the evaluation order undeﬁned? It is not really undeﬁned, it is unspeciﬁed Well, whatever. Lousy compilers. I think it should give us a warning?

#include <stdio.h> int b(void) {
puts(“3”); return 3; } int c(void) { puts(“4”); return 4; } int main(void) { int a = b() + c(); printf(“%dn”, a); }Easy, it prints 3, 4 and then 7 Actually, this could also be 4, 3 and then 7 Huh? Is the evaluation order undeﬁned? It is not really undeﬁned, it is unspeciﬁed Well, whatever. Lousy compilers. I think it should give us a warning? A warning about what?

#include <stdio.h> int b(void) {
puts(“3”); return 3; } int c(void) { puts(“4”); return 4; } int main(void) { int a = b() + c(); printf(“%dn”, a); }The evaluation order of most expressions in C and C++ are unspeciﬁed, thecompiler can choose to evaluate them in the order that is most optimal for the target platform. This has to do with sequencing again.The code is conforming. This code will either print 3, 4, 7 or 4, 3, 7, depending on the compiler.

#include <stdio.h> int b(void) {
puts(“3”); return 3; } int c(void) { puts(“4”); return 4; } int main(void) { int a = b() + c(); printf(“%dn”, a); }The evaluation order of most expressions in C and C++ are unspeciﬁed, thecompiler can choose to evaluate them in the order that is most optimal for the target platform. This has to do with sequencing again.The code is conforming. This code will either print 3, 4, 7 or 4, 3, 7, depending on the compiler. Life would be so easy if more of my colleagues knew stuff like she does

At this point I think
he has just revealed a shallowunderstanding of C programming, while she hasexcelled in her answers so far.

So what is it that
she seems to understand better than most? • Declaration and Deﬁnition • Calling conventions and activation frames

So what is it that
she seems to understand better than most? • Declaration and Deﬁnition • Calling conventions and activation frames • Sequence points

So what is it that
she seems to understand better than most? • Declaration and Deﬁnition • Calling conventions and activation frames • Sequence points • Memory model

So what is it that
she seems to understand better than most? • Declaration and Deﬁnition • Calling conventions and activation frames • Sequence points • Memory model • Optimization

So what is it that
she seems to understand better than most? • Declaration and Deﬁnition • Calling conventions and activation frames • Sequence points • Memory model • Optimization • Knowledge of different C standards

Sequence PointsA sequence point is
a point in the programsexecution sequence where all previous side-effects shall have taken place and where allsubsequent side-effects shall not have taken place(5.1.2.3)

Sequence Points - Rule 1Between
the previous and next sequence point anobject shall have its stored value modified at mostonce by the evaluation of an expression. (6.5) a = a++ this is undefined!

#include <stdio.h>struct X { int
a; char b; int c; };int main(void){ printf("%dn", sizeof(int)); printf("%dn", sizeof(char)); printf("%dn", sizeof(struct X));} It will print 4, 1 and 12 Indeed, it is exactly what I get on my machine Well of course, because sizeof returns the number of bytes. And in Cint is 32 bits or 4 bytes, char is one byte and when the the size of structs are always rounded up to multiples of 4

#include <stdio.h>struct X { int
a; char b; int c; };int main(void){ printf("%dn", sizeof(int)); printf("%dn", sizeof(char)); printf("%dn", sizeof(struct X));} It will print 4, 1 and 12 Indeed, it is exactly what I get on my machine Well of course, because sizeof returns the number of bytes. And in Cint is 32 bits or 4 bytes, char is one byte and when the the size of structs are always rounded up to multiples of 4 ok

#include <stdio.h>struct X { int
a; char b; int c; };int main(void){ printf("%dn", sizeof(int)); printf("%dn", sizeof(char)); printf("%dn", sizeof(struct X));} It will print 4, 1 and 12 Indeed, it is exactly what I get on my machine Well of course, because sizeof returns the number of bytes. And in Cint is 32 bits or 4 bytes, char is one byte and when the the size of structs are always rounded up to multiples of 4 ok do you want another ice cream?

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%dn", sizeof(int)); printf("%dn", sizeof(char)); printf("%dn", sizeof(struct X)); } Hmm... ﬁrst of all, let’s ﬁx the code. The return type of sizeof issize_t which is not the same as int, so %d is a poor speciﬁer to use in the format string for printf here

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%dn", sizeof(int)); printf("%dn", sizeof(char)); printf("%dn", sizeof(struct X)); } Hmm... ﬁrst of all, let’s ﬁx the code. The return type of sizeof issize_t which is not the same as int, so %d is a poor speciﬁer to use in the format string for printf here ok, what should speciﬁer should we use?

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%dn", sizeof(int)); printf("%dn", sizeof(char)); printf("%dn", sizeof(struct X)); } Hmm... ﬁrst of all, let’s ﬁx the code. The return type of sizeof issize_t which is not the same as int, so %d is a poor speciﬁer to use in the format string for printf here ok, what should speciﬁer should we use? Thats a bit tricky. size_t is an unsigned integer type, but on say 32-bit machines it is usually an unsigned int and on 64-bit machines it is usually an unsigned long. In C99 however, they introduced a new speciﬁer for printing size_t values, so %zu might be an option.

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%dn", sizeof(int)); printf("%dn", sizeof(char)); printf("%dn", sizeof(struct X)); } Hmm... ﬁrst of all, let’s ﬁx the code. The return type of sizeof issize_t which is not the same as int, so %d is a poor speciﬁer to use in the format string for printf here ok, what should speciﬁer should we use? Thats a bit tricky. size_t is an unsigned integer type, but on say 32-bit machines it is usually an unsigned int and on 64-bit machines it is usually an unsigned long. In C99 however, they introduced a new speciﬁer for printing size_t values, so %zu might be an option.ok, let’s ﬁx the printf issue, and then you can try to answer the question

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } Now it all depends on the platform and the compile time optionsprovided. The only thing we know for sure is that sizeof char is 1. Do you assume a 64-bit machine?

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } Now it all depends on the platform and the compile time optionsprovided. The only thing we know for sure is that sizeof char is 1. Do you assume a 64-bit machine? Yes, I have a 64-bit machine running in 32-bit compatibility mode.

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } Now it all depends on the platform and the compile time optionsprovided. The only thing we know for sure is that sizeof char is 1. Do you assume a 64-bit machine? Yes, I have a 64-bit machine running in 32-bit compatibility mode. Then I would like to guess that this prints 4, 1, 12 due to word alignment

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } Now it all depends on the platform and the compile time optionsprovided. The only thing we know for sure is that sizeof char is 1. Do you assume a 64-bit machine? Yes, I have a 64-bit machine running in 32-bit compatibility mode. Then I would like to guess that this prints 4, 1, 12 due to word alignment But that of course also depends also on compilation ﬂags. It could be 4, 1, 9 if you ask the compiler to pack the structs, eg -fpack-struct in gcc.

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } 4, 1, 12 is indeed what I get on my machine. Why 12? It is very expensive to work on subword data types, so the compiler will optimizethe code by making sure that c is on a word boundary by adding some padding. Also elements in an array of struct X will now align on word-boundaries.

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } 4, 1, 12 is indeed what I get on my machine. Why 12? It is very expensive to work on subword data types, so the compiler will optimizethe code by making sure that c is on a word boundary by adding some padding. Also elements in an array of struct X will now align on word-boundaries. Why is it expensive to work on values that are not aligned?

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } 4, 1, 12 is indeed what I get on my machine. Why 12? It is very expensive to work on subword data types, so the compiler will optimize the code by making sure that c is on a word boundary by adding some padding. Also elements in an array of struct X will now align on word-boundaries. Why is it expensive to work on values that are not aligned? The instruction set of most processors are optimized for moving a word of data between memory and CPU. Suppose you want to change a value crossing a word boundary, you wouldneed to read two words, mask out the value, change the value, mask and write back two words. Perhaps 10 times slower. Remember, C is focused on execution speed.

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } so what if I add a char d to the struct? If you add it to the end of the struct, my guess is that the size of the struct becomes 16 on your machine. This is ﬁrst of all because 13 would be a not soefﬁcient size, what if you have an array of struct X objects? But if you add it just after char b, then 12 is a more plausible answer.

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } so what if I add a char d to the struct? If you add it to the end of the struct, my guess is that the size of the struct becomes 16 on your machine. This is ﬁrst of all because 13 would be a not soefﬁcient size, what if you have an array of struct X objects? But if you add it just after char b, then 12 is a more plausible answer. So why doesn’t the compiler reorder the members in the structure to optimize memory usage, and execution speed?

#include <stdio.h> struct X {
int a; char b; int c; }; int main(void) { printf("%zun", sizeof(int)); printf("%zun", sizeof(char)); printf("%zun", sizeof(struct X)); } so what if I add a char d to the struct? If you add it to the end of the struct, my guess is that the size of the struct becomes 16 on your machine. This is ﬁrst of all because 13 would be a not soefﬁcient size, what if you have an array of struct X objects? But if you add it just after char b, then 12 is a more plausible answer. So why doesn’t the compiler reorder the members in the structure to optimize memory usage, and execution speed? Some languages actually do that, but C and C++ don’t.