KEMBAR78
Deep C | PDF
Deep C (and C++)
                                     by Olve Maudal and Jon Jagger




                                        http://www.noaanews.noaa.gov/stories2005/images/rov-hercules-titanic.jpg




Programming is hard. Programming correct C and C++ is particularly hard. Indeed, both in C
and certainly in C++, it is uncommon to see a screenful containing only well defined and
conforming code. Why do professional programmers write code like this? Because most
programmers do not have a deep understanding of the language they are using. While they
sometimes know that certain things are undefined or unspecified, they often do not know why
it is so. In these slides we will study small code snippets in C and C++, and use them to discuss
the fundamental building blocks, limitations and underlying design philosophies of these
wonderful but dangerous programming languages.

                                             October 2011
Suppose you are about to interview a candidate for a position as
C programmer for various embedded platforms. As part of the
interview you might want to check whether the candidate has a
deep understanding of the programming language or not... here
is a great code snippet to get the conversation started:
Suppose you are about to interview a candidate for a position as
C programmer for various embedded platforms. As part of the
interview you might want to check whether the candidate has a
deep understanding of the programming language or not... here
is 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 as
C programmer for various embedded platforms. As part of the
interview you might want to check whether the candidate has a
deep understanding of the programming language or not... here
is 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);
                     }
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);
                     }
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 start
demonstrating 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 start
demonstrating 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 elaborates
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:
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 file.
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 file.

                              And when linked with a standard library, it will find a
                             definition 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 file.

                              And when linked with a standard library, it will find a
                             definition 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 file.

                              And when linked with a standard library, it will find a
                             definition 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 defined 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 undefined 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 defined 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 undefined 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 definitions does not hurt.
What will happen if you try to compile, link and run this program?
                     int main()
                     {
                         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);
                      }

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 the
above 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 the
above 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 the
above 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 the
above 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 the
above 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 the
above 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 the
above program on my machine:

   $ cc -std=c89 -c foo.c
   $ cc foo.o
   $ ./a.out
   42
   $ echo $?
   3
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 the
above program on my machine:

   $ cc -std=c89 -c foo.c           $ cc -std=c99 -c foo.c
   $ cc foo.o
   $ ./a.out
   42
   $ echo $?
   3
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 the
above program on my machine:

   $ cc -std=c89 -c foo.c           $ cc -std=c99 -c foo.c
   $ cc foo.o                       $ cc foo.o
   $ ./a.out
   42
   $ echo $?
   3
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 the
above program on my machine:

   $ cc -std=c89 -c foo.c           $ cc -std=c99 -c foo.c
   $ cc foo.o                       $ cc foo.o
   $ ./a.out                        $ ./a.out
   42
   $ echo $?
   3
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 the
above program on my machine:

   $ cc -std=c89 -c foo.c           $ cc -std=c99 -c foo.c
   $ cc foo.o                       $ cc foo.o
   $ ./a.out                        $ ./a.out
   42                               42
   $ echo $?
   3
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 the
above program on my machine:

   $ cc -std=c89 -c foo.c           $ cc -std=c99 -c foo.c
   $ cc foo.o                       $ cc foo.o
   $ ./a.out                        $ ./a.out
   42                               42
   $ echo $?                        $ echo $?
   3
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 the
above program on my machine:

   $ cc -std=c89 -c foo.c           $ cc -std=c99 -c foo.c
   $ cc foo.o                       $ cc foo.o
   $ ./a.out                        $ ./a.out
   42                               42
   $ echo $?                        $ echo $?
   3                                0
Is there any difference between these two candidates?
Is there any difference between these two candidates?




 Not much, yet, but I really like her answers so far.
Now suppose they are not really candidates. Perhaps they
are stereotypes for engineers working in your organization?
Now suppose they are not really candidates. Perhaps they
are stereotypes for engineers working in your organization?
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 deep
understanding of the programming language they are using?
Let’s find out how deep their knowledge of C and C++ is...
Let’s find out how deep their knowledge of C and C++ is...
#include <stdio.h>

void foo(void)
{
    int a = 3;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       it will print 4, then 4, then 4

void foo(void)
{
    int a = 3;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();               it will print 4, then 4, then 4
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    int a = 3;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    static int a = 3;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       it will print 4, then 5, then 6

void foo(void)
{
    static int a = 3;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();               it will print 4, then 5, then 6
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    static int a = 3;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    static int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    static int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    static int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       eh, is it undefined? do you get garbage values?

void foo(void)
{
    static int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       eh, is it undefined? do you get garbage values?

void foo(void)
                                             No, you get 1, then 2, then 3
{
    static int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       eh, is it undefined? 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);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       eh, is it undefined? 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 0

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       eh, is it undefined? 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 0

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>       eh, is it undefined? 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 0

int main(void)
{
    foo();
    foo();               the standard says that static variables are initialized
    foo();               to 0, so this should print 1, then 2, then 3
}
#include <stdio.h>

void foo(void)
{
    static int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

void foo(void)
{
    int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

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>

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)
{
    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 values

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 values

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 values

int main(void)           the value of a will be undefinded, 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 values

int main(void)           the value of a will be undefinded, 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 values

int main(void)           the value of a will be undefinded, 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>

void foo(void)
{
    int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    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;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    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;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    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);
}

int main(void)
{
    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);
}

int main(void)
{
    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 very
int 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 very
int 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 very
int 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.
#include <stdio.h>

void foo(void)
{
    int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>


void foo(void)
{
    int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>



void foo(void)
{
    int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

static int a;

void foo(void)
{
    int a;
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

static int a;

void foo(void)
{

    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

static int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

static int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

static int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
1, 2, 3
#include <stdio.h>

static int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
1, 2, 3
#include <stdio.h>
                           ok, why?
static int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
1, 2, 3
#include <stdio.h>
                                               ok, why?
static int a;
                         because a is static, and therefore initialized to 0
void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
1, 2, 3
#include <stdio.h>
                                               ok, why?
static int a;
                         because a is static, and therefore initialized to 0
void foo(void)
{                                               I agree...
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
1, 2, 3
#include <stdio.h>
                                               ok, why?
static int a;
                         because a is static, and therefore initialized to 0
void foo(void)
{                                               I agree...
    ++a;
    printf("%dn", a);                         cool!
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

static int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
garbage, garbage, garbage
#include <stdio.h>

int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
garbage, garbage, garbage
#include <stdio.h>
                             why do you think that?
int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
garbage, garbage, garbage
#include <stdio.h>
                              why do you think that?
int a;
                          oh, is it still initialized to 0?
void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    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);
}

int main(void)
{
    foo();
    foo();
    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?
}

int main(void)
{
    foo();
    foo();
    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?
}
                                                         yes
int main(void)
{
    foo();
    foo();
    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?
}
                                                                      yes
int 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?
}
                                                                          yes
int 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?
}
                                                                          yes
int 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...
#include <stdio.h>

int a;

void foo(void)
{
    ++a;
    printf("%dn", a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
#include <stdio.h>

int 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 0

int 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 0

int 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 0

int 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 file 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!
I am now going to show you something cool!


#include <stdio.h>

void foo(void)
{
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out

void foo(void)
{
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void foo(void)
{
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void foo(void)
{                                         Can you explain this behaviour?
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void foo(void)
{                                         Can you explain this behaviour?
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void foo(void)
{                                         Can you explain this behaviour?
    int a;
    printf("%dn", a);
}                                                    eh?

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void 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 the
int 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
                                  42
void 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 the
int 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
                                  42
void foo(void)
{
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void foo(void)
{
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void foo(void)
{                           Nice! I love it!
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void 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)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
I am now going to show you something cool!


#include <stdio.h>                $ cc foo.c && ./a.out
                                  42
void 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
                                   42
void 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 file wants to link with
                          the function). Anyway, I suspect the value printed will be
                          something else if you optimize the code.
#include <stdio.h>       $ cc -O foo.c && ./a.out
                         1606415608
void foo(void)
{
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
#include <stdio.h>       $ cc -O foo.c && ./a.out
                         1606415608
void foo(void)
{
    int a;
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
#include <stdio.h>       $ cc -O foo.c && ./a.out
                         1606415608
void foo(void)
{
    int a;                            Garbage!
    printf("%dn", a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}
So what about this code snippet?
So what about this code snippet?

#include <stdio.h>

void foo(void)
{
    int a = 41;
    a = a++;
    printf("%dn", a);
}

int main(void)
{
    foo();
}
#include <stdio.h>

void foo(void)
{
    int a = 41;
    a = a++;
    printf("%dn", a);
}

int main(void)
{
    foo();
}
#include <stdio.h>       I would never write code like that.

void foo(void)
{
    int a = 41;
    a = a++;
    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++;
    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);
}

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


                         Yeah, I told you - I never write code like that
#include <stdio.h>

void foo(void)
{
    int a = 41;
    a = a++;
    printf("%dn", a);
}

int main(void)
{
    foo();
}
#include <stdio.h>

void foo(void)
{
    int a = 41;
    a = a++;
    printf("%dn", a);
}

int main(void)
{
    foo();
}
#include <stdio.h>       a gets an undefined value

void foo(void)
{
    int a = 41;
    a = a++;
    printf("%dn", a);
}

int main(void)
{
    foo();
}
#include <stdio.h>        a gets an undefined value

void 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 undefined value

void 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 undefined after
                         the assignment and increment because you
int 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 undefined.
#include <stdio.h>                  a gets an undefined value

void 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 undefined after
                                the assignment and increment because you
int 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 undefined.

                         So you say a can be whatever? But I do get 42
#include <stdio.h>                                      a gets an undefined value

void 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 undefined after
                                                    the assignment and increment because you
int 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 undefined.

                                            So you say a can be whatever? But I do get 42

Indeed! a can be 42, 41, 43, 0, 1099, or whatever... I am not surprised that your machine gives
you 42... what else can it be here? Or perhaps the compiler choose 42 whenever a value is
undefined ;-)
So what about this code snippet?
So what about this code snippet?
#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);
}
#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);
}
#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
#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
#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 undefined?
#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 undefined?

                       It is not really undefined, it is unspecified
#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 undefined?

                       It is not really undefined, it is unspecified

        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 undefined?

                       It is not really undefined, it is unspecified

        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);
}
#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);
}
#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 unspecified, the
compiler 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 unspecified, the
compiler 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 shallow
understanding of C programming, while she has
excelled in her answers so far.
So what is it that she seems to understand better than most?
So what is it that she seems to understand better than most?



               • Declaration and Definition
So what is it that she seems to understand better than most?



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



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



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



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



               • Declaration and Definition
               • Calling conventions and activation frames
               • Sequence points
               • Memory model
               • Optimization
               • Knowledge of different C standards
We’d like to share some things about:




      Sequence points
      Different C standards
What do these code snippets print?
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);


2   int a=41; a++ & printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);


2   int a=41; a++ & printf("%dn", a);


3   int a=41; a++ && printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);


2   int a=41; a++ & printf("%dn", a);


3   int a=41; a++ && printf("%dn", a);



4   int a=41; if (a++ < 42) printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);


2   int a=41; a++ & printf("%dn", a);


3   int a=41; a++ && printf("%dn", a);



4   int a=41; if (a++ < 42) printf("%dn", a);


5   int a=41; a = a++; printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);            42

2   int a=41; a++ & printf("%dn", a);


3   int a=41; a++ && printf("%dn", a);



4   int a=41; if (a++ < 42) printf("%dn", a);


5   int a=41; a = a++; printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);            42

2   int a=41; a++ & printf("%dn", a);           undefined

3   int a=41; a++ && printf("%dn", a);



4   int a=41; if (a++ < 42) printf("%dn", a);


5   int a=41; a = a++; printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);            42

2   int a=41; a++ & printf("%dn", a);           undefined

3   int a=41; a++ && printf("%dn", a);          42

4   int a=41; if (a++ < 42) printf("%dn", a);


5   int a=41; a = a++; printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);            42

2   int a=41; a++ & printf("%dn", a);           undefined

3   int a=41; a++ && printf("%dn", a);          42

4   int a=41; if (a++ < 42) printf("%dn", a);   42

5   int a=41; a = a++; printf("%dn", a);
What do these code snippets print?

1   int a=41; a++; printf("%dn", a);            42

2   int a=41; a++ & printf("%dn", a);           undefined

3   int a=41; a++ && printf("%dn", a);          42

4   int a=41; if (a++ < 42) printf("%dn", a);   42

5   int a=41; a = a++; printf("%dn", a);        undefined
What do these code snippets print?

1    int a=41; a++; printf("%dn", a);            42

 2   int a=41; a++ & printf("%dn", a);           undefined

 3   int a=41; a++ && printf("%dn", a);          42

 4   int a=41; if (a++ < 42) printf("%dn", a);   42

 5   int a=41; a = a++; printf("%dn", a);        undefined

When exactly do side-effects take place in C and C++?
Sequence Points
A sequence point is a point in the program's
execution sequence where all previous side-
effects shall have taken place and where all
subsequent side-effects shall not have taken place
(5.1.2.3)
Sequence Points - Rule 1
Between the previous and next sequence point an
object shall have its stored value modified at most
once by the evaluation of an expression. (6.5)


                 a = a++


                this is undefined!
Sequence Points - Rule 2
Furthermore, the prior value shall be read only to
determine the value to be stored. (6.5)


                  a + a++


                 this is undefined!!
Sequence Points

A lot of developers think C has many sequence points
Sequence Points

The reality is that C has very few sequence points.




This helps to maximize optimization opportunities
for the compiler.
/* K&R C */                         // C++ (C++98)

void say_it(a, s)                   #include <cstdio>
     int a;
     char s[];                      struct X {
{                                       int a;
     printf("%s %dn", s, a);           const char * s;
}                                       explicit X(const char * s, int a = 42)
                                            : a(a), s(s) {}
main()                                  void say_it() const {
{                                           std::printf("%s %dn", s, a);
    int a = 42;                         }
    puts("Welcome to classic C");   };
    say_it(a, "the answer is");
}                                   int main()
                                    {
                                        X("the answer is").say_it();
/* C89 */                           }
void say_it(int a, char * s)
                                    // C99
{
    printf("%s %dn", s, a);
                                    struct X
}
                                    {
                                        int a;
main()
                                        char * s;
{
                                    };
    int a = 42;
    puts("Welcome to C89");
                                    int main(void)
    say_it(a, "the answer is");
                                    {
}
                                        puts("Welcome to C99");
                                        struct X x = { .s = "the answer is", .a = 42 };
                                        printf("%s %dn", x.s, x.a);
                                    }
Let’s get back to our two developers...
So what about this code snippet?
So what about this code snippet?
#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));
}
#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));
}
#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
#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
#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 C
int 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 C
int 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 C
int 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));
}
#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));
}
#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... first of all, let’s fix the code. The return type of sizeof is
size_t which is not the same as int, so %d is a poor specifier 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... first of all, let’s fix the code. The return type of sizeof is
size_t which is not the same as int, so %d is a poor specifier to use in
                 the format string for printf here

                            ok, what should specifier 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... first of all, let’s fix the code. The return type of sizeof is
size_t which is not the same as int, so %d is a poor specifier to use in
                 the format string for printf here

                             ok, what should specifier 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 specifier 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... first of all, let’s fix the code. The return type of sizeof is
size_t which is not the same as int, so %d is a poor specifier to use in
                 the format string for printf here

                              ok, what should specifier 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 specifier for printing
                          size_t values, so %zu might be an option.

ok, let’s fix 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("%dn", sizeof(int));
    printf("%dn", sizeof(char));
    printf("%dn", sizeof(struct X));
}
#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));
}
#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 options
provided. 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 options
provided. 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 options
provided. 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 options
provided. 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 flags. 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));
}
#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?
#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.
#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?
#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 would
need 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));
}
#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?
#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 first of all because 13 would be a not so
efficient 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 first of all because 13 would be a not so
efficient 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 first of all because 13 would be a not so
efficient 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.
#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));
}
#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 end of the struct?
#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 end of the struct?

You said your runtime was 64-bit, so a pointer is probably 8 bytes... Maybe the
 struct becomes 20? But perhaps the 64-bit pointer also needs alignment for
                efficiency? Maybe this code will print 4,1,24?
#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 end of the struct?

You said your runtime was 64-bit, so a pointer is probably 8 bytes... Maybe the
 struct becomes 20? But perhaps the 64-bit pointer also needs alignment for
                efficiency? Maybe this code will print 4,1,24?


               Nice answer! It does not matter what I actually get on my
                    machine. I like your argument and your insight.
So what is it that she seems to understand better than most?
So what is it that she seems to understand better than most?




              • Some experience with 32-bit vs 64-bit issues
So what is it that she seems to understand better than most?




              • Some experience with 32-bit vs 64-bit issues
              • Memory alignment
So what is it that she seems to understand better than most?




              • Some experience with 32-bit vs 64-bit issues
              • Memory alignment
              • CPU and memory optimization
So what is it that she seems to understand better than most?




              • Some experience with 32-bit vs 64-bit issues
              • Memory alignment
              • CPU and memory optimization
              • Spirit of C
We’d like to share some things about:




            Memory model
            Optimization
            The spirit of C
Memory Model
static storage
An object whose identifier is declared with external or internal
linkage, or with the storage-class specifier static has static
storage duration. It’s lifetime is the entire execution of the
program... (6.2.4)
                      int * immortal(void)
                      {
                          static int storage = 42;
                          return &storage;
                      }
Memory Model
automatic storage
An object whose identifier is declared with no linkage and
without the storage-class specifier static has automatic
storage duration. ... It’s lifetime extends from entry into the
block with which it is associated until execution of that block
ends in any way. (6.2.4)
                             int * zombie(void)
                             {
                                 auto int storage = 42;
                                 return &storage;
                             }
Memory Model
allocated storage
...storage allocated by calls to calloc, malloc, and realloc...
The lifetime of an allocated object extends from the allocation
to the dealloction. (7.20.3)

                     int * finite(void)
                     {
                         int * ptr = malloc(sizeof *ptr);
                         *ptr = 42;
                         return ptr;
                     }
Optimization
By default you should compile with optimization
on. Forcing the compiler to work harder helps it
find more potential problems.
opt.c                      opt.c

#include <stdio.h>         #include <stdio.h>

int main(void)             int main(void)
{                          {
    int a;                     int a;
    printf("%dn", a);         printf("%dn", a);
}                          }


>cc -Wall opt.c            >cc -Wall -O opt.c
                           warning: ‘a’ is uninitialized

no warning!
The Spirit of C
There are many facets of the spirit of C, but the
essence is a community sentiment of the underlying
principles upon which the C language is based
(C Rationale Introduction)
    Trust the programmer
     Keep the language small and simple
     Provide only one way to do an operation
     Make it fast, even if it is not guaranteed to be portable
     Maintain conceptual simplicity
     Don’t prevent the programmer from doing what needs
 to be done
Let’s ask our developers about C++
On a scale from 1 to 10, how do you rate your understanding of C++?
On a scale from 1 to 10, how do you rate your understanding of C++?
On a scale from 1 to 10, how do you rate your understanding of C++?




               I rate myself as 8 or 9
On a scale from 1 to 10, how do you rate your understanding of C++?




               I rate myself as 8 or 9
On a scale from 1 to 10, how do you rate your understanding of C++?




               I rate myself as 8 or 9




               4, maybe 5, I have just so much more to learn about C++
On a scale from 1 to 10, how do you rate your understanding of C++?




               I rate myself as 8 or 9




               4, maybe 5, I have just so much more to learn about C++
On a scale from 1 to 10, how do you rate your understanding of C++?




               I rate myself as 8 or 9




               4, maybe 5, I have just so much more to learn about C++




                                          7
So what about this code snippet?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main(void)
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main(void)
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main(void)
{
    std::cout << sizeof(X) << std::endl;
}

This struct is a POD (Plain Old Data) struct and it is guaranteed by the C++
                   standard to behave just like a struct in C.
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main(void)
{
    std::cout << sizeof(X) << std::endl;
}

This struct is a POD (Plain Old Data) struct and it is guaranteed by the C++
                   standard to behave just like a struct in C.

So on your machine? I guess this will still print 12.
#include <iostream>

     struct X
     {
         int a;
         char b;
         int c;
     };

     int main(void)
     {
         std::cout << sizeof(X) << std::endl;
     }

     This struct is a POD (Plain Old Data) struct and it is guaranteed by the C++
                        standard to behave just like a struct in C.

     So on your machine? I guess this will still print 12.


And by the way, it looks weird to specify func(void) instead of func() as void is
   the default in C++. This is also true when defining the main function. Of
 course, no kittens are hurt by this, it just looks like the code is written by a
                die-hard C programmer struggling to learn C++
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main(void)
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

    This program will print 12
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

    This program will print 12

                                      ok
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

    This program will print 12

                                                      ok


                           So what if I add a member function?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;


};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

      Eh, can you do that in C++? I think you must use a class.
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

      Eh, can you do that in C++? I think you must use a class.

       What is the difference between a class and a struct in C++?
#include <iostream>

         struct X
         {
             int a;
             char b;
             int c;

               void set_value(int v) { a = v; }
         };

         int main()
         {
             std::cout << sizeof(X) << std::endl;
         }

                Eh, can you do that in C++? I think you must use a class.

                   What is the difference between a class and a struct in C++?

Eh, in a class you can have member functions, while I don’t think you can have member
  functions on structs. Or maybe you can? Is it the default visibility that is different?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

Anyway, now this code will print 16. Because there
        will be a pointer to the function.
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

Anyway, now this code will print 16. Because there
        will be a pointer to the function.
                                                     ok?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

Anyway, now this code will print 16. Because there
        will be a pointer to the function.
                                                          ok?


                         so what if I add two more functions?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }


};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

           I guess it will print 24? Two more pointers?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}

           I guess it will print 24? Two more pointers?

                        On my machine it prints much less than 24
#include <iostream>

    struct X
    {
        int a;
        char b;
        int c;

         void set_value(int v) { a = v; }
         int get_value() { return a; }
         void increase_value() { a++; }
    };

    int main()
    {
        std::cout << sizeof(X) << std::endl;
    }

                I guess it will print 24? Two more pointers?

                              On my machine it prints much less than 24

Ah, of course, it has a table of function pointers and only needs one pointer to
      the table! I do really have a deep understanding of this, I just forgot.
#include <iostream>

    struct X
    {
        int a;
        char b;
        int c;

         void set_value(int v) { a = v; }
         int get_value() { return a; }
         void increase_value() { a++; }
    };

    int main()
    {
        std::cout << sizeof(X) << std::endl;
    }

                I guess it will print 24? Two more pointers?

                              On my machine it prints much less than 24

Ah, of course, it has a table of function pointers and only needs one pointer to
      the table! I do really have a deep understanding of this, I just forgot.

                  Actually, on my machine this code still prints 12.
#include <iostream>

    struct X
    {
        int a;
        char b;
        int c;

         void set_value(int v) { a = v; }
         int get_value() { return a; }
         void increase_value() { a++; }
    };

    int main()
    {
        std::cout << sizeof(X) << std::endl;
    }

                 I guess it will print 24? Two more pointers?

                                  On my machine it prints much less than 24

Ah, of course, it has a table of function pointers and only needs one pointer to
      the table! I do really have a deep understanding of this, I just forgot.

                    Actually, on my machine this code still prints 12.

          Huh? Probably some weird optimization going on,
          perhaps because the functions are never called.
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}


                           So what do you think this code prints?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}


                           So what do you think this code prints?

On you machine? I guess 12 again?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}


                           So what do you think this code prints?

On you machine? I guess 12 again?                   Ok, why?
#include <iostream>

   struct X
   {
       int a;
       char b;
       int c;

        void set_value(int v) { a = v; }
        int get_value() { return a; }
        void increase_value() { a++; }
   };

   int main()
   {
       std::cout << sizeof(X) << std::endl;
   }


                                 So what do you think this code prints?

   On you machine? I guess 12 again?                        Ok, why?

 Because adding member functions like this does not change the size of the
struct. The object does not know about it’s functions, it is the functions that
                          know about the object.
#include <iostream>

   struct X
   {
       int a;
       char b;
       int c;

        void set_value(int v) { a = v; }
        int get_value() { return a; }
        void increase_value() { a++; }
   };

   int main()
   {
       std::cout << sizeof(X) << std::endl;
   }


                                 So what do you think this code prints?

   On you machine? I guess 12 again?                        Ok, why?

 Because adding member functions like this does not change the size of the
struct. The object does not know about it’s functions, it is the functions that
                          know about the object.

  If you rewrite this into C it becomes obvious.
struct X
      {
          int a;
          char b;
          int c;
C++        void set_value(int v) { a = v; }
           int get_value() { return a; }
           void increase_value() { a++; }
      };
struct X
      {
          int a;
          char b;
          int c;
C++        void set_value(int v) { a = v; }
           int get_value() { return a; }
           void increase_value() { a++; }
      };

      struct X
      {
          int a;
          char b;

C     };
          int c;


      void set_value(struct X * this, int v) { this->a = v; }
      int get_value(struct X * this) { return this->a; }
      void increase_value(struct X * this) { this->a++; }


                                                                Like this?
struct X
      {
          int a;
          char b;
          int c;
C++        void set_value(int v) { a = v; }
           int get_value() { return a; }
           void increase_value() { a++; }
      };

      struct X
      {
          int a;
          char b;

C     };
          int c;


      void set_value(struct X * this, int v) { this->a = v; }
      int get_value(struct X * this) { return this->a; }
      void increase_value(struct X * this) { this->a++; }


                                                                            Like this?


               Yeah, just like that, and now it is obvious that functions like this do not change
                                         the size of the type and object.
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}


                                  So what happens now?
#include <iostream>

  struct X
  {
      int a;
      char b;
      int c;

       virtual void set_value(int v) { a = v; }
       int get_value() { return a; }
       void increase_value() { a++; }
  };

  int main()
  {
      std::cout << sizeof(X) << std::endl;
  }


                                      So what happens now?


The size of the type will probably grow. The C++ standard does not say
much about how virtual classes and overriding should be implemented,
but a common approach is to create a virtual table and then you need a
       pointer to it. So in this case add 8 bytes? Does it print 20?
#include <iostream>

  struct X
  {
      int a;
      char b;
      int c;

       virtual void set_value(int v) { a = v; }
       int get_value() { return a; }
       void increase_value() { a++; }
  };

  int main()
  {
      std::cout << sizeof(X) << std::endl;
  }


                                      So what happens now?


The size of the type will probably grow. The C++ standard does not say
much about how virtual classes and overriding should be implemented,
but a common approach is to create a virtual table and then you need a
       pointer to it. So in this case add 8 bytes? Does it print 20?


                                 I get 24 when I run this code snippet
#include <iostream>

        struct X
        {
            int a;
            char b;
            int c;

             virtual void set_value(int v) { a = v; }
             int get_value() { return a; }
             void increase_value() { a++; }
        };

        int main()
        {
            std::cout << sizeof(X) << std::endl;
        }


                                              So what happens now?


      The size of the type will probably grow. The C++ standard does not say
      much about how virtual classes and overriding should be implemented,
      but a common approach is to create a virtual table and then you need a
             pointer to it. So in this case add 8 bytes? Does it print 20?


                                         I get 24 when I run this code snippet

Ah, don’t worry. It is probably just some extra padding to align the pointer
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     int get_value() { return a; }
     void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     virtual int get_value() { return a; }
     virtual void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     virtual int get_value() { return a; }
     virtual void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     virtual int get_value() { return a; }
     virtual void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}


                                  So what happens now?
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     virtual int get_value() { return a; }
     virtual void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}


                                        So what happens now?

My guess is that it still prints 24, as you only need one vtable per class.
#include <iostream>

struct X
{
    int a;
    char b;
    int c;

     virtual void set_value(int v) { a = v; }
     virtual int get_value() { return a; }
     virtual void increase_value() { a++; }
};

int main()
{
    std::cout << sizeof(X) << std::endl;
}


                                        So what happens now?

My guess is that it still prints 24, as you only need one vtable per class.

                                           ok, what is a vtable?
#include <iostream>

      struct X
      {
          int a;
          char b;
          int c;

           virtual void set_value(int v) { a = v; }
           virtual int get_value() { return a; }
           virtual void increase_value() { a++; }
      };

      int main()
      {
          std::cout << sizeof(X) << std::endl;
      }


                                             So what happens now?

     My guess is that it still prints 24, as you only need one vtable per class.

                                                ok, what is a vtable?

     It is a common implementation technique to support one type of
polymorphism in C++. It is basically a jump table for function calls, and with it
           you can override functions when doing class inheritance
let’s consider another code snippet...
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

            class A {
            public:
               A(int sz) { sz_ = sz; v = new B[sz_]; }
               ~A() { delete v; }
               // ...
            private:
               // ...
               B * v;
               int sz_;
            };


Take a look at this piece of code. Pretend like I am a junior C++ programmer
joining your team. Here is a piece of code that I might present to you. Please
  be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
           teach me something about the C++ way of doing things.
#include "B.hpp"

            class A {
            public:
               A(int sz) { sz_ = sz; v = new B[sz_]; }
               ~A() { delete v; }
               // ...
            private:
               // ...
               B * v;
               int sz_;
            };


Take a look at this piece of code. Pretend like I am a junior C++ programmer
joining your team. Here is a piece of code that I might present to you. Please
  be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
           teach me something about the C++ way of doing things.
#include "B.hpp"

                   class A {
                   public:
                      A(int sz) { sz_ = sz; v = new B[sz_]; }
                      ~A() { delete v; }
                      // ...
                   private:
                      // ...
                      B * v;
                      int sz_;
                   };


     Take a look at this piece of code. Pretend like I am a junior C++ programmer
     joining your team. Here is a piece of code that I might present to you. Please
       be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
                teach me something about the C++ way of doing things.

This is a piece of shitty C++ code. Is this your code? First of all....
#include "B.hpp"

                   class A {
                   public:
                      A(int sz) { sz_ = sz; v = new B[sz_]; }
                      ~A() { delete v; }
                      // ...
                   private:
                      // ...
                      B * v;
                      int sz_;
                   };


     Take a look at this piece of code. Pretend like I am a junior C++ programmer
     joining your team. Here is a piece of code that I might present to you. Please
       be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
                teach me something about the C++ way of doing things.

This is a piece of shitty C++ code. Is this your code? First of all....

          never use 2 spaces for indentation.
#include "B.hpp"

                   class A {
                   public:
                      A(int sz) { sz_ = sz; v = new B[sz_]; }
                      ~A() { delete v; }
                      // ...
                   private:
                      // ...
                      B * v;
                      int sz_;
                   };


     Take a look at this piece of code. Pretend like I am a junior C++ programmer
     joining your team. Here is a piece of code that I might present to you. Please
       be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
                teach me something about the C++ way of doing things.

This is a piece of shitty C++ code. Is this your code? First of all....

          never use 2 spaces for indentation.

               The curly brace after class A should definitely start on a new line
#include "B.hpp"

                   class A {
                   public:
                      A(int sz) { sz_ = sz; v = new B[sz_]; }
                      ~A() { delete v; }
                      // ...
                   private:
                      // ...
                      B * v;
                      int sz_;
                   };


     Take a look at this piece of code. Pretend like I am a junior C++ programmer
     joining your team. Here is a piece of code that I might present to you. Please
       be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
                teach me something about the C++ way of doing things.

This is a piece of shitty C++ code. Is this your code? First of all....

          never use 2 spaces for indentation.

               The curly brace after class A should definitely start on a new line

            sz_? I have never seen that naming convention, you should always use the GoF
                            standard _sz or the Microsoft standard m_sz.
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};


           Do you see anything else?
#include "B.hpp"

      class A {
      public:
         A(int sz) { sz_ = sz; v = new B[sz_]; }
         ~A() { delete v; }
         // ...
      private:
         // ...
         B * v;
         int sz_;
      };


                 Do you see anything else?


eh?
#include "B.hpp"

            class A {
            public:
               A(int sz) { sz_ = sz; v = new B[sz_]; }
               ~A() { delete v; }
               // ...
            private:
               // ...
               B * v;
               int sz_;
            };


                         Do you see anything else?


eh?      Are you thinking about using ‘delete[]’ instead of ‘delete’ when
      deleting an array of objects? Well, I am experienced enough to know
         that it is not really needed, modern compilers will handle that.
#include "B.hpp"

            class A {
            public:
               A(int sz) { sz_ = sz; v = new B[sz_]; }
               ~A() { delete v; }
               // ...
            private:
               // ...
               B * v;
               int sz_;
            };


                         Do you see anything else?


eh?      Are you thinking about using ‘delete[]’ instead of ‘delete’ when
      deleting an array of objects? Well, I am experienced enough to know
         that it is not really needed, modern compilers will handle that.



                         Ok? What about the “rule of three”? Do you need
                           to support or disable copying of this object?
#include "B.hpp"

            class A {
            public:
               A(int sz) { sz_ = sz; v = new B[sz_]; }
               ~A() { delete v; }
               // ...
            private:
               // ...
               B * v;
               int sz_;
            };


                         Do you see anything else?


eh?      Are you thinking about using ‘delete[]’ instead of ‘delete’ when
      deleting an array of objects? Well, I am experienced enough to know
         that it is not really needed, modern compilers will handle that.



                          Ok? What about the “rule of three”? Do you need
                            to support or disable copying of this object?


      Yeah, whatever... never heard of the tree-rule but of course if people copy this
        object they might get problems. But I guess that is the spirit of C++... give
                              programmers a really hard time.
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

      class A {
      public:
         A(int sz) { sz_ = sz; v = new B[sz_]; }
         ~A() { delete v; }
         // ...
      private:
         // ...
         B * v;
         int sz_;
      };




And by the way, I guess you know that in C++ all destructors should
 always be declared as virtual. I read it in some book and it is very
   important to avoid slicing when deleting objects of subtypes.
#include "B.hpp"

      class A {
      public:
         A(int sz) { sz_ = sz; v = new B[sz_]; }
         ~A() { delete v; }
         // ...
      private:
         // ...
         B * v;
         int sz_;
      };




And by the way, I guess you know that in C++ all destructors should
 always be declared as virtual. I read it in some book and it is very
   important to avoid slicing when deleting objects of subtypes.



                                          or something like that...
#include "B.hpp"

      class A {
      public:
         A(int sz) { sz_ = sz; v = new B[sz_]; }
         ~A() { delete v; }
         // ...
      private:
         // ...
         B * v;
         int sz_;
      };




And by the way, I guess you know that in C++ all destructors should
 always be declared as virtual. I read it in some book and it is very
   important to avoid slicing when deleting objects of subtypes.



                                          or something like that...




                                          another ice cream perhaps?
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

            class A {
            public:
               A(int sz) { sz_ = sz; v = new B[sz_]; }
               ~A() { delete v; }
               // ...
            private:
               // ...
               B * v;
               int sz_;
            };


Take a look at this piece of code. Pretend like I am a junior C++ programmer
joining your team. Here is a piece of code that I might present to you. Please
  be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
           teach me something about the C++ way of doing things.
#include "B.hpp"

                class A {
                public:
                   A(int sz) { sz_ = sz; v = new B[sz_]; }
                   ~A() { delete v; }
                   // ...
                private:
                   // ...
                   B * v;
                   int sz_;
                };


   Take a look at this piece of code. Pretend like I am a junior C++ programmer
   joining your team. Here is a piece of code that I might present to you. Please
     be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
              teach me something about the C++ way of doing things.

Oh, where should I start... let’s focus on the most important stuff first
#include "B.hpp"

                class A {
                public:
                   A(int sz) { sz_ = sz; v = new B[sz_]; }
                   ~A() { delete v; }
                   // ...
                private:
                   // ...
                   B * v;
                   int sz_;
                };


   Take a look at this piece of code. Pretend like I am a junior C++ programmer
   joining your team. Here is a piece of code that I might present to you. Please
     be pedantic and try to gently introduce me to pitfalls of C++ and perhaps
              teach me something about the C++ way of doing things.

Oh, where should I start... let’s focus on the most important stuff first


        In the destructor. If you use operator new[] you should destroy with operator
      delete[]. With operator delete[] the allocated memory will be deallocated after the
       destructor for every object in the array will be called. Eg, as it stands now, the B
      constructor will be called sz times, but the B destructor will only be called once. In
      this case, bad things will happen if B allocates resources that need to be released in
                                           its destructor.
#include "B.hpp"

                   class A {
                   public:
                      A(int sz) { sz_ = sz; v = new B[sz_]; }
                      ~A() { delete v; }
                      // ...
                   private:
                      // ...
                      B * v;
                      int sz_;
                   };


And the next thing is the often referred to as the “rule of three”. If you need a
 destructor, you probably also need to either implement or disable the copy
  constructor and the assignment operator, the default ones created by the
                      compiler are probably not correct.
#include "B.hpp"

                   class A {
                   public:
                      A(int sz) { sz_ = sz; v = new B[sz_]; }
                      ~A() { delete v; }
                      // ...
                   private:
                      // ...
                      B * v;
                      int sz_;
                   };


And the next thing is the often referred to as the “rule of three”. If you need a
 destructor, you probably also need to either implement or disable the copy
  constructor and the assignment operator, the default ones created by the
                      compiler are probably not correct.


          A perhaps smaller issue, but also important, is to use the member initializer list to
         initialize an object. In the example above it does not really matter much, but when
             member objects are more complex it makes sense to explicitly initialize the
        members (using the initalizer list), rather than letting the object implicitly initialize all
         its member objects to default values, and then assign them some particular value.
#include "B.hpp"

                   class A {
                   public:
                      A(int sz) { sz_ = sz; v = new B[sz_]; }
                      ~A() { delete v; }
                      // ...
                   private:
                      // ...
                      B * v;
                      int sz_;
                   };


And the next thing is the often referred to as the “rule of three”. If you need a
 destructor, you probably also need to either implement or disable the copy
  constructor and the assignment operator, the default ones created by the
                      compiler are probably not correct.


          A perhaps smaller issue, but also important, is to use the member initializer list to
         initialize an object. In the example above it does not really matter much, but when
             member objects are more complex it makes sense to explicitly initialize the
        members (using the initalizer list), rather than letting the object implicitly initialize all
         its member objects to default values, and then assign them some particular value.



             Please fix the code and I will tell you more...
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
  A(int sz) { sz_ = sz; v = new B[sz_]; }
  ~A() { delete[] v; }
  // ...
private:

     // ...
     B * v;
     int sz_;
};
#include "B.hpp"

class A {
public:
  A(int sz) { sz_ = sz; v = new B[sz_]; }
  ~A() { delete[] v; }
  // ...
private:


     // ...
     B * v;
     int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};


       Better
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   virtual ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   virtual ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};


             nah, nah, nah... hold your horses
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   virtual ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};


              nah, nah, nah... hold your horses


     What is the point of having a virtual destructor on a class like this?
     There are no virtual functions so it does not make sense to inherit
      from it. I know that there are programmers who do inherit from
       non-virtual classes, but I suspect they have misunderstood a key
       concept of object orientation. I suggest you remove the virtual
     specifier from the destructor, it indicates that the class is designed
            to be used as a base class - while it obviously is not.
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   virtual ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};


              nah, nah, nah... hold your horses


     What is the point of having a virtual destructor on a class like this?
     There are no virtual functions so it does not make sense to inherit
      from it. I know that there are programmers who do inherit from
       non-virtual classes, but I suspect they have misunderstood a key
       concept of object orientation. I suggest you remove the virtual
     specifier from the destructor, it indicates that the class is designed
            to be used as a base class - while it obviously is not.


    why don’t you fix the initializer list issue instead
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   virtual ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz) { sz_ = sz; v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz) { v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz) { v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz_]) { v = new B[sz_]; }
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz_]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz_]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};




            now we have an initializer list...
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz_]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};


       ouch... but do you see the problem we just introduced?
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz_]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};


       ouch... but do you see the problem we just introduced?

        Are you compiling with -Wall? You should consider -Wextra -
                      pedantic and -Weffc++ as well
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz_]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};


        ouch... but do you see the problem we just introduced?

        Are you compiling with -Wall? You should consider -Wextra -
                      pedantic and -Weffc++ as well


Without warning flags you might not notice the mistake here. But if you
 increase the warning levelsl it will scream the problem in your face...
#include "B.hpp"

                      class A {
                      public:
                         A(int sz) : sz_(sz), v(new B[sz_]) {}
                         ~A() { delete[] v; }
                         // ...
                      private:
                         A(const A &);
                         A & operator=(const A &);
                         // ...
                         B * v;
                         int sz_;
                      };


                               ouch... but do you see the problem we just introduced?

                               Are you compiling with -Wall? You should consider -Wextra -
                                             pedantic and -Weffc++ as well


                       Without warning flags you might not notice the mistake here. But if you
                        increase the warning levelsl it will scream the problem in your face...


A nice rule of thumb is to always write the member initializers in the order they are defined. In
this case, when v(new B[sz_]) is evaluated sz_ is undefined, and then sz_ is initialized with sz.
                   Actually, these things are just too common in C++ code.
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz_]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : sz_(sz), v(new B[sz]) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : v(new B[sz]), sz_(sz) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : v(new B[sz]), sz_(sz) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};
#include "B.hpp"

class A {
public:
   A(int sz) : v(new B[sz]), sz_(sz) {}
   ~A() { delete[] v; }
   // ...
private:
   A(const A &);
   A & operator=(const A &);
   // ...
   B * v;
   int sz_;
};



        Now this looks better! Is there anything else that needs to be
      improved? Perhaps some small stuff that I would like to mention...
#include "B.hpp"

 class A {
 public:
    A(int sz) : v(new B[sz]), sz_(sz) {}
    ~A() { delete[] v; }
    // ...
 private:
    A(const A &);
    A & operator=(const A &);
    // ...
    B * v;
    int sz_;
 };



         Now this looks better! Is there anything else that needs to be
       improved? Perhaps some small stuff that I would like to mention...

When I see bald pointers in C++ it is usually a bad sign. A lot of good C++
 programmers tend to avoid using them like this. In this case of course, it
looks like v is a candidate for being an STL vector or something like that.
#include "B.hpp"

                      class A {
                      public:
                         A(int sz) : v(new B[sz]), sz_(sz) {}
                         ~A() { delete[] v; }
                         // ...
                      private:
                         A(const A &);
                         A & operator=(const A &);
                         // ...
                         B * v;
                         int sz_;
                      };



                               Now this looks better! Is there anything else that needs to be
                             improved? Perhaps some small stuff that I would like to mention...

                     When I see bald pointers in C++ it is usually a bad sign. A lot of good C++
                      programmers tend to avoid using them like this. In this case of course, it
                     looks like v is a candidate for being an STL vector or something like that.

You seem to use different naming conventions for private member variables, but as long as it is
  private stuff I think you can do whatever you want. But I guess either postfixing all member
variables with _ is fine, so is prefixing with m_, but you should never just prefix with _ because
      you might stumble into reserved naming conventions for C, Posix and/or compilers.
So what is it that she seems to understand better than most?
So what is it that she seems to understand better than most?



               • the connection between C and C++
So what is it that she seems to understand better than most?



               • the connection between C and C++
               • some techniques for polymorphism
So what is it that she seems to understand better than most?



               • the connection between C and C++
               • some techniques for polymorphism
               • how to initialize objects properly
So what is it that she seems to understand better than most?



               • the connection between C and C++
               • some techniques for polymorphism
               • how to initialize objects properly
               • rule of three
So what is it that she seems to understand better than most?



               • the connection between C and C++
               • some techniques for polymorphism
               • how to initialize objects properly
               • rule of three
               • operator new[] and delete[]
So what is it that she seems to understand better than most?



               • the connection between C and C++
               • some techniques for polymorphism
               • how to initialize objects properly
               • rule of three
               • operator new[] and delete[]
               • common naming conventions
We’d like to share some things about:




           Object lifetime
           The rule of three
           The vtable
proper object initialization
assignment is not the same as initialization

struct A
{
    A() { puts("A()"); }
    A(int v) { puts("A(int)"); }
   ~A() { puts("~A()"); }           bad style
};                                  A()
                                    A(int)
struct X
{                                   ~A()
    X(int v) { a=v; }               ~A()
    X(long v) : a(v) { }            good style
    A a;
};                                  A(int)
                                    ~A()
int main()
{
    puts("bad style");
    { X slow(int(2)); }
    puts("good style");
    { X fast(long(2)); }
}
object lifetime
A basic principle of C++ is that the operations performed when
an object’s life ends are the exact reverse of the operations
performed when the object’s life starts.

   struct A                    int main()
   {                           {
       A() { puts("A()"); }        C obj;
      ~A() { puts("~A()"); }   }
   };

   struct B                    A()
   {                           B()
       B() { puts("B()"); }
      ~B() { puts("~B()"); }   ~B()
   };                          ~A()
   struct C
   {
       A a;
       B b;
   };
object lifetime
A basic principle of C++ is that the operations performed when
an object’s life ends are the exact reverse of the operations
performed when the object’s life starts.

        struct A                           int main()
        {                                  {
            A() : id(count++)                  A array[4];
            {                              }
               printf("A(%d)n", id);
            }
            ~A()                           A(0)
            {
                 printf("~A(%d)n", id);   A(1)
            }                              A(2)
            int id;                        A(3)
            static int count;
        };                                 ~A(3)
                                           ~A(2)
                                           ~A(1)
                                           ~A(0)
object lifetime
  A basic principle of C++ is that the operations performed when
  an object’s life ends are the exact reverse of the operations
  performed when the object’s life starts.
                                   int main()                  int main()
struct A                           {                           {
{                                      A * array = new A[4];       A * array = new A[4];
    A() : id(count++)                  delete[] array;             delete array;
    {                              }                           }
       printf("A(%d)n", id);
    }
    ~A()                                                       A(0)
                                   A(0)
    {                                                          A(1)
         printf("~A(%d)n", id);   A(1)
    }                                                          A(2)
                                   A(2)
    int id;                                                    A(3)
    static int count;              A(3)
};                                                             ~A(0)
                                   ~A(3)
                                   ~A(2)
                                   ~A(1)
                                   ~A(0)
The Rule of Three
If a class defines a copy constructor


          class wibble_ptr {
          public:
              wibble_ptr()
                   : ptr(new wibble), count(new int(1)) {
              }
              wibble_ptr(const wibble_ptr & other)
                   : ptr(other.ptr), count(other.count) {
                   (*count)++;
              }
              .
              .
              .
              .
              .
              .
              .
              .
              .
              .
          private:
              wibble * ptr;
              int * count;
          };
The Rule of Three
If a class defines a copy constructor, a copy assignment
operator

          class wibble_ptr {
          public:
              wibble_ptr()
                   : ptr(new wibble), count(new int(1)) {
              }
              .
              .
              .
              .
              wibble_ptr & operator=(const wibble_ptr & rhs) {
                   wibble_ptr copy(rhs);
                   swap(copy);
                   return *this;
              }
              .
              .
              .
              .
              .
          private:
              wibble * ptr;
              int * count;
          };
The Rule of Three
If a class defines a copy constructor, a copy assignment
operator, or a destructor

          class wibble_ptr {
          public:
              wibble_ptr()
                   : ptr(new wibble), count(new int(1)) {
              }
              .
              .
              .
              .
              .
              .
              .
              .
              .
              ~wibble_ptr() {
                   if (--(*count) == 0)
                       delete ptr;
              }
              .
          private:
              wibble * ptr;
              int * count;
          };
The Rule of Three
If a class defines a copy constructor, a copy assignment
operator, or a destructor, then it should define all three.

          class wibble_ptr {
          public:
              wibble_ptr()
                   : ptr(new wibble), count(new int(1)) {
              }
              wibble_ptr(const wibble_ptr & other)
                   : ptr(other.ptr), count(other.count) {
                   (*count)++;
              }
              wibble_ptr & operator=(const wibble_ptr & rhs) {
                   wibble_ptr copy(rhs);
                   swap(copy);
                   return *this;
              }
              ~wibble_ptr() {
                   if (--(*count) == 0)
                       delete ptr;
              }
              ...
          private:
              wibble * ptr;
              int * count;
          };
The vtable
struct base
{
                                         0      f       base::f() {}
    virtual void f();
    virtual void g();       vptr
    int a,b;
};                           a           1     g
struct derived : base
{
                             b                base      base::g() {}
    virtual void g();   base object          vtable
    virtual void h();
    int c;
};

void poly(base * ptr)
{
    ptr->f();               vptr         0     f
    ptr->g();
                                                       derived::g() {}
}
                             a           1     g
int main()
{                            b           2     h
    poly(&base());                                     derived::h() {}
    poly(&derived());
}                            c               derived
                        derived object       vtable
The vtable
                                                          base::f() {}
struct base
{
              void f();
     virtual void g();        vptr         0     g        base::g() {}
     int a,b;
};                             a                base
                                               vtable
struct derived : base
{
                               b
    virtual void g();     base object
    virtual void h();
    int c;
};

void poly(base * ptr)
{                                                        derived::g() {}
    ptr->f();
    ptr->g();
                              vptr         0      g
}
                               a           1     h
int main()                                               derived::h() {}
{
    poly(&base());
                               b               derived
    poly(&derived());                          vtable
}                              c
                          derived object
Would it be useful if more of your colleagues have a deep
understanding of the programming language they are using?




We are not suggesting that all your C and C++ programmers
in your organization need a deep understanding of the
language. But you certainly need a critical mass of
programmers that care about their profession and constantly
keep updating themselves and always strive for a better
understanding of their programming language.
Let’s get back to our two developers...
So what is the biggest difference between these two
developers?
So what is the biggest difference between these two
developers?
Current knowledge of the language?
So what is the biggest difference between these two
developers?
Current knowledge of the language?       No!
So what is the biggest difference between these two
developers?
Current knowledge of the language?       No!
           It is their attitude to learning!
When was the last time you did a course about programming?
When was the last time you did a course about programming?

What do you mean? I learned programming at university and now I
        am learning by doing. What more do you need?
When was the last time you did a course about programming?

What do you mean? I learned programming at university and now I
        am learning by doing. What more do you need?

              So what kinds of books are you reading?
When was the last time you did a course about programming?

 What do you mean? I learned programming at university and now I
         am learning by doing. What more do you need?

                So what kinds of books are you reading?


Books? I don’t need books. I look up stuff on internet when I need it.
When was the last time you did a course about programming?

 What do you mean? I learned programming at university and now I
         am learning by doing. What more do you need?

                So what kinds of books are you reading?


Books? I don’t need books. I look up stuff on internet when I need it.


            Do you discuss programming with your colleagues?
When was the last time you did a course about programming?

 What do you mean? I learned programming at university and now I
         am learning by doing. What more do you need?

                So what kinds of books are you reading?


Books? I don’t need books. I look up stuff on internet when I need it.


            Do you discuss programming with your colleagues?


       They are all stupid, I have nothing to learn from them...
You seem to know a lot about C and C++? How come?
You seem to know a lot about C and C++? How come?

     I am learning new things every day, I really enjoy it.
You seem to know a lot about C and C++? How come?

     I am learning new things every day, I really enjoy it.

    I occasionally follow C and C++ discussions on stack overflow,
                     comp.lang.c and comp.lang.c++
You seem to know a lot about C and C++? How come?

     I am learning new things every day, I really enjoy it.

    I occasionally follow C and C++ discussions on stack overflow,
                     comp.lang.c and comp.lang.c++

      I am a member of a local C and C++ Users Group, we have
                     meetings once in a while
You seem to know a lot about C and C++? How come?

     I am learning new things every day, I really enjoy it.

    I occasionally follow C and C++ discussions on stack overflow,
                     comp.lang.c and comp.lang.c++

      I am a member of a local C and C++ Users Group, we have
                     meetings once in a while

 I read books. Lots of books. Did you know that James Grenning just
  came out with a great book about Test-Driven Development in C?
You seem to know a lot about C and C++? How come?

     I am learning new things every day, I really enjoy it.

    I occasionally follow C and C++ discussions on stack overflow,
                     comp.lang.c and comp.lang.c++

      I am a member of a local C and C++ Users Group, we have
                     meetings once in a while

 I read books. Lots of books. Did you know that James Grenning just
  came out with a great book about Test-Driven Development in C?

      I have to admit that I visit WG14 and WG21 once in a while
You seem to know a lot about C and C++? How come?

     I am learning new things every day, I really enjoy it.

    I occasionally follow C and C++ discussions on stack overflow,
                     comp.lang.c and comp.lang.c++

      I am a member of a local C and C++ Users Group, we have
                     meetings once in a while

 I read books. Lots of books. Did you know that James Grenning just
  came out with a great book about Test-Driven Development in C?

      I have to admit that I visit WG14 and WG21 once in a while

 I am a member of ACCU, for those who care about professionalism in
  programming, I read Overload, C Vu and discussions on accu-general
You seem to know a lot about C and C++? How come?

         I am learning new things every day, I really enjoy it.

       I occasionally follow C and C++ discussions on stack overflow,
                        comp.lang.c and comp.lang.c++

         I am a member of a local C and C++ Users Group, we have
                        meetings once in a while

    I read books. Lots of books. Did you know that James Grenning just
     came out with a great book about Test-Driven Development in C?

          I have to admit that I visit WG14 and WG21 once in a while

    I am a member of ACCU, for those who care about professionalism in
     programming, I read Overload, C Vu and discussions on accu-general

And whenever I get a chance I attend classes teaching C and C++. It not
always because I learn so much from the slides and the teacher, it is often
  through discussions with other learners that I expand my knowledge.
You seem to know a lot about C and C++? How come?

                  I am learning new things every day, I really enjoy it.

                I occasionally follow C and C++ discussions on stack overflow,
                                 comp.lang.c and comp.lang.c++

                  I am a member of a local C and C++ Users Group, we have
                                 meetings once in a while

             I read books. Lots of books. Did you know that James Grenning just
              came out with a great book about Test-Driven Development in C?

                   I have to admit that I visit WG14 and WG21 once in a while

             I am a member of ACCU, for those who care about professionalism in
              programming, I read Overload, C Vu and discussions on accu-general

         And whenever I get a chance I attend classes teaching C and C++. It not
         always because I learn so much from the slides and the teacher, it is often
           through discussions with other learners that I expand my knowledge.

But perhaps the best source of knowledge is working closely with my colleagues and
          try to learn from them while contributing with my knowledge.
Summary
Summary

• compiler and linker
Summary

• compiler and linker
• declaration vs definition
Summary

• compiler and linker
• declaration vs definition
• activation frame
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
• optimization
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
• optimization
• something about C++
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
• optimization
• something about C++
• proper initialization of objects
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
• optimization
• something about C++
• proper initialization of objects
• object lifetimes
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
• optimization
• something about C++
• proper initialization of objects
• object lifetimes
• vtables
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
• optimization
• something about C++
• proper initialization of objects
• object lifetimes
• vtables
• rule of 3
Summary

• compiler and linker
• declaration vs definition
• activation frame
• memory segments
• memory alignment
• sequence points
• evaluation order
• undefined vs unspecified
• optimization
• something about C++
• proper initialization of objects
• object lifetimes
• vtables
• rule of 3
• ... and something about attitude and professionalism
!
Eh?
Eh?   Yes?
Eh?                                              Yes?


 I really love programming, but I realize now that perhaps I am not
behaving as a true professional. Any advice on how to get started to
                 get a deep knowledge of C and C++?
Eh?                                               Yes?


    I really love programming, but I realize now that perhaps I am not
   behaving as a true professional. Any advice on how to get started to
                    get a deep knowledge of C and C++?

First of all you must realize that programming is a continuous learning
process, it does not matter how much you know, there is always much
more to learn. The next thing to realize is that professional
programming is first of all a team activity, you must work and develop
together with your colleagues. Think about programming as a team
sport, where nobody can win a whole match alone.
Eh?                                               Yes?


    I really love programming, but I realize now that perhaps I am not
   behaving as a true professional. Any advice on how to get started to
                    get a deep knowledge of C and C++?

First of all you must realize that programming is a continuous learning
process, it does not matter how much you know, there is always much
more to learn. The next thing to realize is that professional
programming is first of all a team activity, you must work and develop
together with your colleagues. Think about programming as a team
sport, where nobody can win a whole match alone.


Ok, I need to think about that...
Eh?                                               Yes?


                  I really love programming, but I realize now that perhaps I am not
                 behaving as a true professional. Any advice on how to get started to
                                  get a deep knowledge of C and C++?

              First of all you must realize that programming is a continuous learning
              process, it does not matter how much you know, there is always much
              more to learn. The next thing to realize is that professional
              programming is first of all a team activity, you must work and develop
              together with your colleagues. Think about programming as a team
              sport, where nobody can win a whole match alone.


              Ok, I need to think about that...


 Having said that. Make it a habit to once in a while take a look at the assembly
output actually produced by snippets of C and C++. There are a lot of surprising
things to discover. Use a debugger, step through code, study how memory is used and
look at the instructions actually executed by the processor.
Any books, sites, courses and conferences about C and C++ you
                    would like to recommend?
Any books, sites, courses and conferences about C and C++ you
                    would like to recommend?

  To learn modern ways of developing software, I recommend “Test-Driven
  Development for Embedded C” by James Grenning. For deep C
  knowledge, Peter van der Linden wrote a book called “Expert C
  programming” two decades ago, but the content is still quite relevant. For C
  ++ I recommend you start with “Effective C++” by Scott Meyers and “C++
  coding standards” by Herb Sutter and Andrei Alexandrescu.
Any books, sites, courses and conferences about C and C++ you
                    would like to recommend?

  To learn modern ways of developing software, I recommend “Test-Driven
  Development for Embedded C” by James Grenning. For deep C
  knowledge, Peter van der Linden wrote a book called “Expert C
  programming” two decades ago, but the content is still quite relevant. For C
  ++ I recommend you start with “Effective C++” by Scott Meyers and “C++
  coding standards” by Herb Sutter and Andrei Alexandrescu.

   Also, whenever you get a chance to go to a course about C and C++, do
   so. If your attitude is right, there is just so much to learn from both the
   instructor and the other students at the course.
Any books, sites, courses and conferences about C and C++ you
                      would like to recommend?

     To learn modern ways of developing software, I recommend “Test-Driven
     Development for Embedded C” by James Grenning. For deep C
     knowledge, Peter van der Linden wrote a book called “Expert C
     programming” two decades ago, but the content is still quite relevant. For C
     ++ I recommend you start with “Effective C++” by Scott Meyers and “C++
     coding standards” by Herb Sutter and Andrei Alexandrescu.

      Also, whenever you get a chance to go to a course about C and C++, do
      so. If your attitude is right, there is just so much to learn from both the
      instructor and the other students at the course.


And finally, I would recommend that you get yourself involved in user groups and
communities for programmers. In particular I would recommend the ACCU
(accu.org), they are very much focused on C and C++ programming. Did you
know they host a conference in Oxford every spring where professional
programmers from all around the world meet to discuss programming for a
week? Perhaps I see you there in April next year?
Any books, sites, courses and conferences about C and C++ you
                      would like to recommend?

     To learn modern ways of developing software, I recommend “Test-Driven
     Development for Embedded C” by James Grenning. For deep C
     knowledge, Peter van der Linden wrote a book called “Expert C
     programming” two decades ago, but the content is still quite relevant. For C
     ++ I recommend you start with “Effective C++” by Scott Meyers and “C++
     coding standards” by Herb Sutter and Andrei Alexandrescu.

      Also, whenever you get a chance to go to a course about C and C++, do
      so. If your attitude is right, there is just so much to learn from both the
      instructor and the other students at the course.


And finally, I would recommend that you get yourself involved in user groups and
communities for programmers. In particular I would recommend the ACCU
(accu.org), they are very much focused on C and C++ programming. Did you
know they host a conference in Oxford every spring where professional
programmers from all around the world meet to discuss programming for a
week? Perhaps I see you there in April next year?

Thanks!
Any books, sites, courses and conferences about C and C++ you
                      would like to recommend?

     To learn modern ways of developing software, I recommend “Test-Driven
     Development for Embedded C” by James Grenning. For deep C
     knowledge, Peter van der Linden wrote a book called “Expert C
     programming” two decades ago, but the content is still quite relevant. For C
     ++ I recommend you start with “Effective C++” by Scott Meyers and “C++
     coding standards” by Herb Sutter and Andrei Alexandrescu.

      Also, whenever you get a chance to go to a course about C and C++, do
      so. If your attitude is right, there is just so much to learn from both the
      instructor and the other students at the course.


And finally, I would recommend that you get yourself involved in user groups and
communities for programmers. In particular I would recommend the ACCU
(accu.org), they are very much focused on C and C++ programming. Did you
know they host a conference in Oxford every spring where professional
programmers from all around the world meet to discuss programming for a
week? Perhaps I see you there in April next year?

Thanks!
                                                           Good luck!
http://www.sharpshirter.com/assets/images/sharkpunchashgrey1.jpg

Deep C

  • 1.
    Deep C (andC++) by Olve Maudal and Jon Jagger http://www.noaanews.noaa.gov/stories2005/images/rov-hercules-titanic.jpg Programming is hard. Programming correct C and C++ is particularly hard. Indeed, both in C and certainly in C++, it is uncommon to see a screenful containing only well defined and conforming code. Why do professional programmers write code like this? Because most programmers do not have a deep understanding of the language they are using. While they sometimes know that certain things are undefined or unspecified, they often do not know why it is so. In these slides we will study small code snippets in C and C++, and use them to discuss the fundamental building blocks, limitations and underlying design philosophies of these wonderful but dangerous programming languages. October 2011
  • 4.
    Suppose you areabout to interview a candidate for a position as C programmer for various embedded platforms. As part of the interview you might want to check whether the candidate has a deep understanding of the programming language or not... here is a great code snippet to get the conversation started:
  • 5.
    Suppose you areabout to interview a candidate for a position as C programmer for various embedded platforms. As part of the interview you might want to check whether the candidate has a deep understanding of the programming language or not... here is a great code snippet to get the conversation started: int main() { int a = 42; printf(“%dn”, a); }
  • 6.
    Suppose you areabout to interview a candidate for a position as C programmer for various embedded platforms. As part of the interview you might want to check whether the candidate has a deep understanding of the programming language or not... here is 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?
  • 7.
    What will happenif you try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }
  • 8.
    What will happenif you try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); } One candidate might say:
  • 9.
    What will happenif 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.
  • 10.
    What will happenif 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...
  • 11.
    What will happenif you try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }
  • 12.
    What will happenif 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 start demonstrating a deeper understanding. She might say things like:
  • 13.
    What will happenif 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 start demonstrating 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.
  • 14.
    What will happenif you try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); } and then she elaborates a bit by saying:
  • 15.
    What will happenif 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:
  • 16.
    What will happenif 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 file.
  • 17.
    What will happenif 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 file. And when linked with a standard library, it will find a definition of printf()that accidentally will match the implicit declaration.
  • 18.
    What will happenif 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 file. And when linked with a standard library, it will find a definition of printf()that accidentally will match the implicit declaration. So the program above will actually compile, link and run.
  • 19.
    What will happenif 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 file. And when linked with a standard library, it will find a definition 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.
  • 20.
    What will happenif 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:
  • 21.
    What will happenif 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 defined 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 undefined garbage value.
  • 22.
    What will happenif 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 defined 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 undefined 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.
  • 23.
    What will happenif 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:
  • 24.
    What will happenif 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 definitions does not hurt.
  • 25.
    What will happenif you try to compile, link and run this program? int main() { int a = 42; printf(“%dn”, a); }
  • 26.
    What will happenif you try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }
  • 27.
    What will happenif 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.
  • 28.
    What will happenif you try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }
  • 29.
    What will happenif you try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }
  • 30.
    What will happenif 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
  • 31.
    What will happenif you try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }
  • 32.
    What will happenif you try to compile, link and run this program? int main(void) { int a = 42; printf(“%dn”, a); }
  • 33.
    What will happenif you try to compile, link and run this program? #include <stdio.h> int main(void) { int a = 42; printf(“%dn”, a); }
  • 34.
    What will happenif 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?
  • 35.
    What will happenif 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 the above program on my machine:
  • 36.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c
  • 37.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o
  • 38.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out
  • 39.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out 42
  • 40.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out 42 $ echo $?
  • 41.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc foo.o $ ./a.out 42 $ echo $? 3
  • 42.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc -std=c99 -c foo.c $ cc foo.o $ ./a.out 42 $ echo $? 3
  • 43.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc -std=c99 -c foo.c $ cc foo.o $ cc foo.o $ ./a.out 42 $ echo $? 3
  • 44.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc -std=c99 -c foo.c $ cc foo.o $ cc foo.o $ ./a.out $ ./a.out 42 $ echo $? 3
  • 45.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc -std=c99 -c foo.c $ cc foo.o $ cc foo.o $ ./a.out $ ./a.out 42 42 $ echo $? 3
  • 46.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc -std=c99 -c foo.c $ cc foo.o $ cc foo.o $ ./a.out $ ./a.out 42 42 $ echo $? $ echo $? 3
  • 47.
    What will happenif 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 the above program on my machine: $ cc -std=c89 -c foo.c $ cc -std=c99 -c foo.c $ cc foo.o $ cc foo.o $ ./a.out $ ./a.out 42 42 $ echo $? $ echo $? 3 0
  • 48.
    Is there anydifference between these two candidates?
  • 49.
    Is there anydifference between these two candidates? Not much, yet, but I really like her answers so far.
  • 50.
    Now suppose theyare not really candidates. Perhaps they are stereotypes for engineers working in your organization?
  • 51.
    Now suppose theyare not really candidates. Perhaps they are stereotypes for engineers working in your organization?
  • 52.
    Now suppose theyare not really candidates. Perhaps they are stereotypes for engineers working in your organization? Would it be useful if most of your colleagues have a deep understanding of the programming language they are using?
  • 53.
    Let’s find outhow deep their knowledge of C and C++ is...
  • 54.
    Let’s find outhow deep their knowledge of C and C++ is...
  • 55.
    #include <stdio.h> void foo(void) { int a = 3; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 56.
    #include <stdio.h> it will print 4, then 4, then 4 void foo(void) { int a = 3; ++a; printf("%dn", a); } int main(void) { foo(); it will print 4, then 4, then 4 foo(); foo(); }
  • 57.
    #include <stdio.h> void foo(void) { int a = 3; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 58.
    #include <stdio.h> void foo(void) { static int a = 3; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 59.
    #include <stdio.h> it will print 4, then 5, then 6 void foo(void) { static int a = 3; ++a; printf("%dn", a); } int main(void) { foo(); it will print 4, then 5, then 6 foo(); foo(); }
  • 60.
    #include <stdio.h> void foo(void) { static int a = 3; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 61.
    #include <stdio.h> void foo(void) { static int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 62.
    #include <stdio.h> void foo(void) { static int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 63.
    #include <stdio.h> void foo(void) { static int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 64.
    #include <stdio.h> eh, is it undefined? do you get garbage values? void foo(void) { static int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 65.
    #include <stdio.h> eh, is it undefined? do you get garbage values? void foo(void) No, you get 1, then 2, then 3 { static int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 66.
    #include <stdio.h> eh, is it undefined? 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); } int main(void) { foo(); foo(); foo(); }
  • 67.
    #include <stdio.h> eh, is it undefined? 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 0 int main(void) { foo(); foo(); foo(); }
  • 68.
    #include <stdio.h> eh, is it undefined? 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 0 int main(void) { foo(); foo(); foo(); }
  • 69.
    #include <stdio.h> eh, is it undefined? 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 0 int main(void) { foo(); foo(); the standard says that static variables are initialized foo(); to 0, so this should print 1, then 2, then 3 }
  • 70.
    #include <stdio.h> void foo(void) { static int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 71.
    #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 72.
    #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 73.
    #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 74.
    Now you get1, then 1, then 1 #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 75.
    Now you get1, 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(); }
  • 76.
    Now you get1, 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(); }
  • 77.
    Now you get1, 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(); }
  • 78.
    Now you get1, 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 values int main(void) { foo(); foo(); foo(); }
  • 79.
    Now you get1, 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 values int main(void) { foo(); foo(); foo(); }
  • 80.
    Now you get1, 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 values int main(void) the value of a will be undefinded, 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.
  • 81.
    Now you get1, 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 values int main(void) the value of a will be undefinded, 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
  • 82.
    Now you get1, 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 values int main(void) the value of a will be undefinded, 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
  • 83.
    #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 84.
    #include <stdio.h> Why do you think static variables are set to 0, while auto variables are not initialized? void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 85.
    #include <stdio.h> Why do you think static variables are set to 0, while auto variables are not initialized? void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 86.
    #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); } int main(void) { foo(); foo(); foo(); }
  • 87.
    #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); } int main(void) { foo(); foo(); foo(); }
  • 88.
    #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 very int main(void) strong focus on execution speed. { foo(); foo(); foo(); }
  • 89.
    #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 very int 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.
  • 90.
    #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 very int 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.
  • 91.
    #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 92.
    #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 93.
    #include <stdio.h> void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 94.
    #include <stdio.h> static inta; void foo(void) { int a; ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 95.
    #include <stdio.h> static inta; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 96.
    #include <stdio.h> static inta; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 97.
    #include <stdio.h> static inta; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 98.
    #include <stdio.h> static inta; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 99.
    1, 2, 3 #include<stdio.h> static int a; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 100.
    1, 2, 3 #include<stdio.h> ok, why? static int a; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 101.
    1, 2, 3 #include<stdio.h> ok, why? static int a; because a is static, and therefore initialized to 0 void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 102.
    1, 2, 3 #include<stdio.h> ok, why? static int a; because a is static, and therefore initialized to 0 void foo(void) { I agree... ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 103.
    1, 2, 3 #include<stdio.h> ok, why? static int a; because a is static, and therefore initialized to 0 void foo(void) { I agree... ++a; printf("%dn", a); cool! } int main(void) { foo(); foo(); foo(); }
  • 104.
    #include <stdio.h> static inta; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 105.
    #include <stdio.h> int a; voidfoo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 106.
    #include <stdio.h> int a; voidfoo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 107.
    #include <stdio.h> int a; voidfoo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 108.
    garbage, garbage, garbage #include<stdio.h> int a; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 109.
    garbage, garbage, garbage #include<stdio.h> why do you think that? int a; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 110.
    garbage, garbage, garbage #include<stdio.h> why do you think that? int a; oh, is it still initialized to 0? void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 111.
    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); } int main(void) { foo(); foo(); foo(); }
  • 112.
    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? } int main(void) { foo(); foo(); foo(); }
  • 113.
    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? } yes int main(void) { foo(); foo(); foo(); }
  • 114.
    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? } yes int main(void) { do you know the difference between this code foo(); snippet and the previous code snippet (with static foo(); before int a)? foo(); }
  • 115.
    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? } yes int 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.
  • 116.
    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? } yes int 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...
  • 117.
    #include <stdio.h> int a; voidfoo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 118.
    #include <stdio.h> int a; voidfoo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 119.
    it will print1, 2, 3, the variable is still statically #include <stdio.h> allocated and it will be set to 0 int a; void foo(void) { ++a; printf("%dn", a); } int main(void) { foo(); foo(); foo(); }
  • 120.
    it will print1, 2, 3, the variable is still statically #include <stdio.h> allocated and it will be set to 0 int 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(); }
  • 121.
    it will print1, 2, 3, the variable is still statically #include <stdio.h> allocated and it will be set to 0 int 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 file 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.
  • 123.
    I am nowgoing to show you something cool!
  • 124.
    I am nowgoing to show you something cool! #include <stdio.h> void foo(void) { int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 125.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out void foo(void) { int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 126.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void foo(void) { int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 127.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void foo(void) { Can you explain this behaviour? int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 128.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void foo(void) { Can you explain this behaviour? int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 129.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void foo(void) { Can you explain this behaviour? int a; printf("%dn", a); } eh? void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 130.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void 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 the int 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. }
  • 131.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void 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 the int 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...
  • 132.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void foo(void) { int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 133.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void foo(void) { int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 134.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void foo(void) { Nice! I love it! int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 135.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void 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) { int a = 42; } int main(void) { bar(); foo(); }
  • 136.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void 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(); }
  • 137.
    I am nowgoing to show you something cool! #include <stdio.h> $ cc foo.c && ./a.out 42 void 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 file wants to link with the function). Anyway, I suspect the value printed will be something else if you optimize the code.
  • 138.
    #include <stdio.h> $ cc -O foo.c && ./a.out 1606415608 void foo(void) { int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 139.
    #include <stdio.h> $ cc -O foo.c && ./a.out 1606415608 void foo(void) { int a; printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 140.
    #include <stdio.h> $ cc -O foo.c && ./a.out 1606415608 void foo(void) { int a; Garbage! printf("%dn", a); } void bar(void) { int a = 42; } int main(void) { bar(); foo(); }
  • 141.
    So what aboutthis code snippet?
  • 142.
    So what aboutthis code snippet? #include <stdio.h> void foo(void) { int a = 41; a = a++; printf("%dn", a); } int main(void) { foo(); }
  • 143.
    #include <stdio.h> void foo(void) { int a = 41; a = a++; printf("%dn", a); } int main(void) { foo(); }
  • 144.
    #include <stdio.h> I would never write code like that. void foo(void) { int a = 41; a = a++; printf("%dn", a); } int main(void) { foo(); }
  • 145.
    #include <stdio.h> I would never write code like that. void foo(void) That’s nice to hear! { int a = 41; a = a++; printf("%dn", a); } int main(void) { foo(); }
  • 146.
    #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(); }
  • 147.
    #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(); }
  • 148.
    #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(); }
  • 149.
    #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
  • 150.
    #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!
  • 151.
    #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 undefined.
  • 152.
    #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 undefined. Yeah, I told you - I never write code like that
  • 153.
    #include <stdio.h> void foo(void) { int a = 41; a = a++; printf("%dn", a); } int main(void) { foo(); }
  • 154.
    #include <stdio.h> void foo(void) { int a = 41; a = a++; printf("%dn", a); } int main(void) { foo(); }
  • 155.
    #include <stdio.h> a gets an undefined value void foo(void) { int a = 41; a = a++; printf("%dn", a); } int main(void) { foo(); }
  • 156.
    #include <stdio.h> a gets an undefined value void 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(); }
  • 157.
    #include <stdio.h> a gets an undefined value void 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 undefined after the assignment and increment because you int 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 undefined.
  • 158.
    #include <stdio.h> a gets an undefined value void 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 undefined after the assignment and increment because you int 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 undefined. So you say a can be whatever? But I do get 42
  • 159.
    #include <stdio.h> a gets an undefined value void 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 undefined after the assignment and increment because you int 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 undefined. So you say a can be whatever? But I do get 42 Indeed! a can be 42, 41, 43, 0, 1099, or whatever... I am not surprised that your machine gives you 42... what else can it be here? Or perhaps the compiler choose 42 whenever a value is undefined ;-)
  • 160.
    So what aboutthis code snippet?
  • 161.
    So what aboutthis code snippet? #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); }
  • 162.
    #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); }
  • 163.
    #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
  • 164.
    #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
  • 165.
    #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 undefined?
  • 166.
    #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 undefined? It is not really undefined, it is unspecified
  • 167.
    #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 undefined? It is not really undefined, it is unspecified Well, whatever. Lousy compilers. I think it should give us a warning?
  • 168.
    #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 undefined? It is not really undefined, it is unspecified Well, whatever. Lousy compilers. I think it should give us a warning? A warning about what?
  • 169.
    #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); }
  • 170.
    #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); }
  • 171.
    #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 unspecified, the compiler 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.
  • 172.
    #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 unspecified, the compiler 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
  • 174.
    At this pointI think he has just revealed a shallow understanding of C programming, while she has excelled in her answers so far.
  • 175.
    So what isit that she seems to understand better than most?
  • 176.
    So what isit that she seems to understand better than most? • Declaration and Definition
  • 177.
    So what isit that she seems to understand better than most? • Declaration and Definition • Calling conventions and activation frames
  • 178.
    So what isit that she seems to understand better than most? • Declaration and Definition • Calling conventions and activation frames • Sequence points
  • 179.
    So what isit that she seems to understand better than most? • Declaration and Definition • Calling conventions and activation frames • Sequence points • Memory model
  • 180.
    So what isit that she seems to understand better than most? • Declaration and Definition • Calling conventions and activation frames • Sequence points • Memory model • Optimization
  • 181.
    So what isit that she seems to understand better than most? • Declaration and Definition • Calling conventions and activation frames • Sequence points • Memory model • Optimization • Knowledge of different C standards
  • 182.
    We’d like toshare some things about: Sequence points Different C standards
  • 183.
    What do thesecode snippets print?
  • 184.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a);
  • 185.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 2 int a=41; a++ & printf("%dn", a);
  • 186.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 2 int a=41; a++ & printf("%dn", a); 3 int a=41; a++ && printf("%dn", a);
  • 187.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 2 int a=41; a++ & printf("%dn", a); 3 int a=41; a++ && printf("%dn", a); 4 int a=41; if (a++ < 42) printf("%dn", a);
  • 188.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 2 int a=41; a++ & printf("%dn", a); 3 int a=41; a++ && printf("%dn", a); 4 int a=41; if (a++ < 42) printf("%dn", a); 5 int a=41; a = a++; printf("%dn", a);
  • 189.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 42 2 int a=41; a++ & printf("%dn", a); 3 int a=41; a++ && printf("%dn", a); 4 int a=41; if (a++ < 42) printf("%dn", a); 5 int a=41; a = a++; printf("%dn", a);
  • 190.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 42 2 int a=41; a++ & printf("%dn", a); undefined 3 int a=41; a++ && printf("%dn", a); 4 int a=41; if (a++ < 42) printf("%dn", a); 5 int a=41; a = a++; printf("%dn", a);
  • 191.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 42 2 int a=41; a++ & printf("%dn", a); undefined 3 int a=41; a++ && printf("%dn", a); 42 4 int a=41; if (a++ < 42) printf("%dn", a); 5 int a=41; a = a++; printf("%dn", a);
  • 192.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 42 2 int a=41; a++ & printf("%dn", a); undefined 3 int a=41; a++ && printf("%dn", a); 42 4 int a=41; if (a++ < 42) printf("%dn", a); 42 5 int a=41; a = a++; printf("%dn", a);
  • 193.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 42 2 int a=41; a++ & printf("%dn", a); undefined 3 int a=41; a++ && printf("%dn", a); 42 4 int a=41; if (a++ < 42) printf("%dn", a); 42 5 int a=41; a = a++; printf("%dn", a); undefined
  • 194.
    What do thesecode snippets print? 1 int a=41; a++; printf("%dn", a); 42 2 int a=41; a++ & printf("%dn", a); undefined 3 int a=41; a++ && printf("%dn", a); 42 4 int a=41; if (a++ < 42) printf("%dn", a); 42 5 int a=41; a = a++; printf("%dn", a); undefined When exactly do side-effects take place in C and C++?
  • 195.
    Sequence Points A sequencepoint is a point in the program's execution sequence where all previous side- effects shall have taken place and where all subsequent side-effects shall not have taken place (5.1.2.3)
  • 196.
    Sequence Points -Rule 1 Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. (6.5) a = a++ this is undefined!
  • 197.
    Sequence Points -Rule 2 Furthermore, the prior value shall be read only to determine the value to be stored. (6.5) a + a++ this is undefined!!
  • 198.
    Sequence Points A lotof developers think C has many sequence points
  • 199.
    Sequence Points The realityis that C has very few sequence points. This helps to maximize optimization opportunities for the compiler.
  • 200.
    /* K&R C*/ // C++ (C++98) void say_it(a, s) #include <cstdio> int a; char s[]; struct X { { int a; printf("%s %dn", s, a); const char * s; } explicit X(const char * s, int a = 42) : a(a), s(s) {} main() void say_it() const { { std::printf("%s %dn", s, a); int a = 42; } puts("Welcome to classic C"); }; say_it(a, "the answer is"); } int main() { X("the answer is").say_it(); /* C89 */ } void say_it(int a, char * s) // C99 { printf("%s %dn", s, a); struct X } { int a; main() char * s; { }; int a = 42; puts("Welcome to C89"); int main(void) say_it(a, "the answer is"); { } puts("Welcome to C99"); struct X x = { .s = "the answer is", .a = 42 }; printf("%s %dn", x.s, x.a); }
  • 201.
    Let’s get backto our two developers...
  • 202.
    So what aboutthis code snippet?
  • 203.
    So what aboutthis code snippet? #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)); }
  • 204.
    #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)); }
  • 205.
    #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
  • 206.
    #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
  • 207.
    #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 C int 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
  • 208.
    #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 C int 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
  • 209.
    #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 C int 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?
  • 210.
    #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)); }
  • 211.
    #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)); }
  • 212.
    #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... first of all, let’s fix the code. The return type of sizeof is size_t which is not the same as int, so %d is a poor specifier to use in the format string for printf here
  • 213.
    #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... first of all, let’s fix the code. The return type of sizeof is size_t which is not the same as int, so %d is a poor specifier to use in the format string for printf here ok, what should specifier should we use?
  • 214.
    #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... first of all, let’s fix the code. The return type of sizeof is size_t which is not the same as int, so %d is a poor specifier to use in the format string for printf here ok, what should specifier 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 specifier for printing size_t values, so %zu might be an option.
  • 215.
    #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... first of all, let’s fix the code. The return type of sizeof is size_t which is not the same as int, so %d is a poor specifier to use in the format string for printf here ok, what should specifier 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 specifier for printing size_t values, so %zu might be an option. ok, let’s fix the printf issue, and then you can try to answer the question
  • 216.
    #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)); }
  • 217.
    #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)); }
  • 218.
    #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 options provided. The only thing we know for sure is that sizeof char is 1. Do you assume a 64-bit machine?
  • 219.
    #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 options provided. 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.
  • 220.
    #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 options provided. 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
  • 221.
    #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 options provided. 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 flags. It could be 4, 1, 9 if you ask the compiler to pack the structs, eg -fpack-struct in gcc.
  • 222.
    #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)); }
  • 223.
    #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?
  • 224.
    #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.
  • 225.
    #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?
  • 226.
    #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 would need 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.
  • 227.
    #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)); }
  • 228.
    #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?
  • 229.
    #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 first of all because 13 would be a not so efficient 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.
  • 230.
    #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 first of all because 13 would be a not so efficient 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?
  • 231.
    #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 first of all because 13 would be a not so efficient 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.
  • 232.
    #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)); }
  • 233.
    #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 end of the struct?
  • 234.
    #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 end of the struct? You said your runtime was 64-bit, so a pointer is probably 8 bytes... Maybe the struct becomes 20? But perhaps the 64-bit pointer also needs alignment for efficiency? Maybe this code will print 4,1,24?
  • 235.
    #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 end of the struct? You said your runtime was 64-bit, so a pointer is probably 8 bytes... Maybe the struct becomes 20? But perhaps the 64-bit pointer also needs alignment for efficiency? Maybe this code will print 4,1,24? Nice answer! It does not matter what I actually get on my machine. I like your argument and your insight.
  • 236.
    So what isit that she seems to understand better than most?
  • 237.
    So what isit that she seems to understand better than most? • Some experience with 32-bit vs 64-bit issues
  • 238.
    So what isit that she seems to understand better than most? • Some experience with 32-bit vs 64-bit issues • Memory alignment
  • 239.
    So what isit that she seems to understand better than most? • Some experience with 32-bit vs 64-bit issues • Memory alignment • CPU and memory optimization
  • 240.
    So what isit that she seems to understand better than most? • Some experience with 32-bit vs 64-bit issues • Memory alignment • CPU and memory optimization • Spirit of C
  • 241.
    We’d like toshare some things about: Memory model Optimization The spirit of C
  • 242.
    Memory Model static storage Anobject whose identifier is declared with external or internal linkage, or with the storage-class specifier static has static storage duration. It’s lifetime is the entire execution of the program... (6.2.4) int * immortal(void) { static int storage = 42; return &storage; }
  • 243.
    Memory Model automatic storage Anobject whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration. ... It’s lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (6.2.4) int * zombie(void) { auto int storage = 42; return &storage; }
  • 244.
    Memory Model allocated storage ...storageallocated by calls to calloc, malloc, and realloc... The lifetime of an allocated object extends from the allocation to the dealloction. (7.20.3) int * finite(void) { int * ptr = malloc(sizeof *ptr); *ptr = 42; return ptr; }
  • 245.
    Optimization By default youshould compile with optimization on. Forcing the compiler to work harder helps it find more potential problems. opt.c opt.c #include <stdio.h> #include <stdio.h> int main(void) int main(void) { { int a; int a; printf("%dn", a); printf("%dn", a); } } >cc -Wall opt.c >cc -Wall -O opt.c warning: ‘a’ is uninitialized no warning!
  • 246.
    The Spirit ofC There are many facets of the spirit of C, but the essence is a community sentiment of the underlying principles upon which the C language is based (C Rationale Introduction) Trust the programmer Keep the language small and simple Provide only one way to do an operation Make it fast, even if it is not guaranteed to be portable Maintain conceptual simplicity Don’t prevent the programmer from doing what needs to be done
  • 247.
    Let’s ask ourdevelopers about C++
  • 249.
    On a scalefrom 1 to 10, how do you rate your understanding of C++?
  • 250.
    On a scalefrom 1 to 10, how do you rate your understanding of C++?
  • 251.
    On a scalefrom 1 to 10, how do you rate your understanding of C++? I rate myself as 8 or 9
  • 252.
    On a scalefrom 1 to 10, how do you rate your understanding of C++? I rate myself as 8 or 9
  • 253.
    On a scalefrom 1 to 10, how do you rate your understanding of C++? I rate myself as 8 or 9 4, maybe 5, I have just so much more to learn about C++
  • 254.
    On a scalefrom 1 to 10, how do you rate your understanding of C++? I rate myself as 8 or 9 4, maybe 5, I have just so much more to learn about C++
  • 255.
    On a scalefrom 1 to 10, how do you rate your understanding of C++? I rate myself as 8 or 9 4, maybe 5, I have just so much more to learn about C++ 7
  • 256.
    So what aboutthis code snippet? #include <iostream> struct X { int a; char b; int c; }; int main(void) { std::cout << sizeof(X) << std::endl; }
  • 257.
    #include <iostream> struct X { int a; char b; int c; }; int main(void) { std::cout << sizeof(X) << std::endl; }
  • 258.
    #include <iostream> struct X { int a; char b; int c; }; int main(void) { std::cout << sizeof(X) << std::endl; } This struct is a POD (Plain Old Data) struct and it is guaranteed by the C++ standard to behave just like a struct in C.
  • 259.
    #include <iostream> struct X { int a; char b; int c; }; int main(void) { std::cout << sizeof(X) << std::endl; } This struct is a POD (Plain Old Data) struct and it is guaranteed by the C++ standard to behave just like a struct in C. So on your machine? I guess this will still print 12.
  • 260.
    #include <iostream> struct X { int a; char b; int c; }; int main(void) { std::cout << sizeof(X) << std::endl; } This struct is a POD (Plain Old Data) struct and it is guaranteed by the C++ standard to behave just like a struct in C. So on your machine? I guess this will still print 12. And by the way, it looks weird to specify func(void) instead of func() as void is the default in C++. This is also true when defining the main function. Of course, no kittens are hurt by this, it just looks like the code is written by a die-hard C programmer struggling to learn C++
  • 261.
    #include <iostream> struct X { int a; char b; int c; }; int main(void) { std::cout << sizeof(X) << std::endl; }
  • 262.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; }
  • 263.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; }
  • 264.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; } This program will print 12
  • 265.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; } This program will print 12 ok
  • 266.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; } This program will print 12 ok So what if I add a member function?
  • 267.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; }
  • 268.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; }
  • 269.
    #include <iostream> struct X { int a; char b; int c; }; int main() { std::cout << sizeof(X) << std::endl; }
  • 270.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 271.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 272.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; } Eh, can you do that in C++? I think you must use a class.
  • 273.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; } Eh, can you do that in C++? I think you must use a class. What is the difference between a class and a struct in C++?
  • 274.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; } Eh, can you do that in C++? I think you must use a class. What is the difference between a class and a struct in C++? Eh, in a class you can have member functions, while I don’t think you can have member functions on structs. Or maybe you can? Is it the default visibility that is different?
  • 275.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; } Anyway, now this code will print 16. Because there will be a pointer to the function.
  • 276.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; } Anyway, now this code will print 16. Because there will be a pointer to the function. ok?
  • 277.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; } Anyway, now this code will print 16. Because there will be a pointer to the function. ok? so what if I add two more functions?
  • 278.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 279.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 280.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 281.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 282.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 283.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } I guess it will print 24? Two more pointers?
  • 284.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } I guess it will print 24? Two more pointers? On my machine it prints much less than 24
  • 285.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } I guess it will print 24? Two more pointers? On my machine it prints much less than 24 Ah, of course, it has a table of function pointers and only needs one pointer to the table! I do really have a deep understanding of this, I just forgot.
  • 286.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } I guess it will print 24? Two more pointers? On my machine it prints much less than 24 Ah, of course, it has a table of function pointers and only needs one pointer to the table! I do really have a deep understanding of this, I just forgot. Actually, on my machine this code still prints 12.
  • 287.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } I guess it will print 24? Two more pointers? On my machine it prints much less than 24 Ah, of course, it has a table of function pointers and only needs one pointer to the table! I do really have a deep understanding of this, I just forgot. Actually, on my machine this code still prints 12. Huh? Probably some weird optimization going on, perhaps because the functions are never called.
  • 288.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 289.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 290.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what do you think this code prints?
  • 291.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what do you think this code prints? On you machine? I guess 12 again?
  • 292.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what do you think this code prints? On you machine? I guess 12 again? Ok, why?
  • 293.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what do you think this code prints? On you machine? I guess 12 again? Ok, why? Because adding member functions like this does not change the size of the struct. The object does not know about it’s functions, it is the functions that know about the object.
  • 294.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what do you think this code prints? On you machine? I guess 12 again? Ok, why? Because adding member functions like this does not change the size of the struct. The object does not know about it’s functions, it is the functions that know about the object. If you rewrite this into C it becomes obvious.
  • 295.
    struct X { int a; char b; int c; C++ void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } };
  • 296.
    struct X { int a; char b; int c; C++ void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; struct X { int a; char b; C }; int c; void set_value(struct X * this, int v) { this->a = v; } int get_value(struct X * this) { return this->a; } void increase_value(struct X * this) { this->a++; } Like this?
  • 297.
    struct X { int a; char b; int c; C++ void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; struct X { int a; char b; C }; int c; void set_value(struct X * this, int v) { this->a = v; } int get_value(struct X * this) { return this->a; } void increase_value(struct X * this) { this->a++; } Like this? Yeah, just like that, and now it is obvious that functions like this do not change the size of the type and object.
  • 298.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 299.
    #include <iostream> struct X { int a; char b; int c; void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 300.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 301.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now?
  • 302.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now? The size of the type will probably grow. The C++ standard does not say much about how virtual classes and overriding should be implemented, but a common approach is to create a virtual table and then you need a pointer to it. So in this case add 8 bytes? Does it print 20?
  • 303.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now? The size of the type will probably grow. The C++ standard does not say much about how virtual classes and overriding should be implemented, but a common approach is to create a virtual table and then you need a pointer to it. So in this case add 8 bytes? Does it print 20? I get 24 when I run this code snippet
  • 304.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now? The size of the type will probably grow. The C++ standard does not say much about how virtual classes and overriding should be implemented, but a common approach is to create a virtual table and then you need a pointer to it. So in this case add 8 bytes? Does it print 20? I get 24 when I run this code snippet Ah, don’t worry. It is probably just some extra padding to align the pointer
  • 305.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 306.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } int get_value() { return a; } void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 307.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } virtual int get_value() { return a; } virtual void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 308.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } virtual int get_value() { return a; } virtual void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; }
  • 309.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } virtual int get_value() { return a; } virtual void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now?
  • 310.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } virtual int get_value() { return a; } virtual void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now? My guess is that it still prints 24, as you only need one vtable per class.
  • 311.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } virtual int get_value() { return a; } virtual void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now? My guess is that it still prints 24, as you only need one vtable per class. ok, what is a vtable?
  • 312.
    #include <iostream> struct X { int a; char b; int c; virtual void set_value(int v) { a = v; } virtual int get_value() { return a; } virtual void increase_value() { a++; } }; int main() { std::cout << sizeof(X) << std::endl; } So what happens now? My guess is that it still prints 24, as you only need one vtable per class. ok, what is a vtable? It is a common implementation technique to support one type of polymorphism in C++. It is basically a jump table for function calls, and with it you can override functions when doing class inheritance
  • 313.
    let’s consider anothercode snippet...
  • 314.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; };
  • 315.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things.
  • 316.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things.
  • 317.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things. This is a piece of shitty C++ code. Is this your code? First of all....
  • 318.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things. This is a piece of shitty C++ code. Is this your code? First of all.... never use 2 spaces for indentation.
  • 319.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things. This is a piece of shitty C++ code. Is this your code? First of all.... never use 2 spaces for indentation. The curly brace after class A should definitely start on a new line
  • 320.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things. This is a piece of shitty C++ code. Is this your code? First of all.... never use 2 spaces for indentation. The curly brace after class A should definitely start on a new line sz_? I have never seen that naming convention, you should always use the GoF standard _sz or the Microsoft standard m_sz.
  • 321.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; };
  • 322.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Do you see anything else?
  • 323.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Do you see anything else? eh?
  • 324.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Do you see anything else? eh? Are you thinking about using ‘delete[]’ instead of ‘delete’ when deleting an array of objects? Well, I am experienced enough to know that it is not really needed, modern compilers will handle that.
  • 325.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Do you see anything else? eh? Are you thinking about using ‘delete[]’ instead of ‘delete’ when deleting an array of objects? Well, I am experienced enough to know that it is not really needed, modern compilers will handle that. Ok? What about the “rule of three”? Do you need to support or disable copying of this object?
  • 326.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Do you see anything else? eh? Are you thinking about using ‘delete[]’ instead of ‘delete’ when deleting an array of objects? Well, I am experienced enough to know that it is not really needed, modern compilers will handle that. Ok? What about the “rule of three”? Do you need to support or disable copying of this object? Yeah, whatever... never heard of the tree-rule but of course if people copy this object they might get problems. But I guess that is the spirit of C++... give programmers a really hard time.
  • 327.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; };
  • 328.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; And by the way, I guess you know that in C++ all destructors should always be declared as virtual. I read it in some book and it is very important to avoid slicing when deleting objects of subtypes.
  • 329.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; And by the way, I guess you know that in C++ all destructors should always be declared as virtual. I read it in some book and it is very important to avoid slicing when deleting objects of subtypes. or something like that...
  • 330.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; And by the way, I guess you know that in C++ all destructors should always be declared as virtual. I read it in some book and it is very important to avoid slicing when deleting objects of subtypes. or something like that... another ice cream perhaps?
  • 331.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; };
  • 332.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things.
  • 333.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things. Oh, where should I start... let’s focus on the most important stuff first
  • 334.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; Take a look at this piece of code. Pretend like I am a junior C++ programmer joining your team. Here is a piece of code that I might present to you. Please be pedantic and try to gently introduce me to pitfalls of C++ and perhaps teach me something about the C++ way of doing things. Oh, where should I start... let’s focus on the most important stuff first In the destructor. If you use operator new[] you should destroy with operator delete[]. With operator delete[] the allocated memory will be deallocated after the destructor for every object in the array will be called. Eg, as it stands now, the B constructor will be called sz times, but the B destructor will only be called once. In this case, bad things will happen if B allocates resources that need to be released in its destructor.
  • 335.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; And the next thing is the often referred to as the “rule of three”. If you need a destructor, you probably also need to either implement or disable the copy constructor and the assignment operator, the default ones created by the compiler are probably not correct.
  • 336.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; And the next thing is the often referred to as the “rule of three”. If you need a destructor, you probably also need to either implement or disable the copy constructor and the assignment operator, the default ones created by the compiler are probably not correct. A perhaps smaller issue, but also important, is to use the member initializer list to initialize an object. In the example above it does not really matter much, but when member objects are more complex it makes sense to explicitly initialize the members (using the initalizer list), rather than letting the object implicitly initialize all its member objects to default values, and then assign them some particular value.
  • 337.
    #include "B.hpp" class A { public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; }; And the next thing is the often referred to as the “rule of three”. If you need a destructor, you probably also need to either implement or disable the copy constructor and the assignment operator, the default ones created by the compiler are probably not correct. A perhaps smaller issue, but also important, is to use the member initializer list to initialize an object. In the example above it does not really matter much, but when member objects are more complex it makes sense to explicitly initialize the members (using the initalizer list), rather than letting the object implicitly initialize all its member objects to default values, and then assign them some particular value. Please fix the code and I will tell you more...
  • 338.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete v; } // ... private: // ... B * v; int sz_; };
  • 339.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: // ... B * v; int sz_; };
  • 340.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: // ... B * v; int sz_; };
  • 341.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: // ... B * v; int sz_; };
  • 342.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: // ... B * v; int sz_; };
  • 343.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 344.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; Better
  • 345.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 346.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } virtual ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 347.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } virtual ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; nah, nah, nah... hold your horses
  • 348.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } virtual ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; nah, nah, nah... hold your horses What is the point of having a virtual destructor on a class like this? There are no virtual functions so it does not make sense to inherit from it. I know that there are programmers who do inherit from non-virtual classes, but I suspect they have misunderstood a key concept of object orientation. I suggest you remove the virtual specifier from the destructor, it indicates that the class is designed to be used as a base class - while it obviously is not.
  • 349.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } virtual ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; nah, nah, nah... hold your horses What is the point of having a virtual destructor on a class like this? There are no virtual functions so it does not make sense to inherit from it. I know that there are programmers who do inherit from non-virtual classes, but I suspect they have misunderstood a key concept of object orientation. I suggest you remove the virtual specifier from the destructor, it indicates that the class is designed to be used as a base class - while it obviously is not. why don’t you fix the initializer list issue instead
  • 350.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } virtual ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 351.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 352.
    #include "B.hpp" class A{ public: A(int sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 353.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz) { sz_ = sz; v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 354.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz) { v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 355.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz) { v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 356.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz_]) { v = new B[sz_]; } ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 357.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz_]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 358.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz_]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; now we have an initializer list...
  • 359.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz_]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; ouch... but do you see the problem we just introduced?
  • 360.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz_]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; ouch... but do you see the problem we just introduced? Are you compiling with -Wall? You should consider -Wextra - pedantic and -Weffc++ as well
  • 361.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz_]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; ouch... but do you see the problem we just introduced? Are you compiling with -Wall? You should consider -Wextra - pedantic and -Weffc++ as well Without warning flags you might not notice the mistake here. But if you increase the warning levelsl it will scream the problem in your face...
  • 362.
    #include "B.hpp" class A { public: A(int sz) : sz_(sz), v(new B[sz_]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; ouch... but do you see the problem we just introduced? Are you compiling with -Wall? You should consider -Wextra - pedantic and -Weffc++ as well Without warning flags you might not notice the mistake here. But if you increase the warning levelsl it will scream the problem in your face... A nice rule of thumb is to always write the member initializers in the order they are defined. In this case, when v(new B[sz_]) is evaluated sz_ is undefined, and then sz_ is initialized with sz. Actually, these things are just too common in C++ code.
  • 363.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz_]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 364.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 365.
    #include "B.hpp" class A{ public: A(int sz) : sz_(sz), v(new B[sz]) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 366.
    #include "B.hpp" class A{ public: A(int sz) : v(new B[sz]), sz_(sz) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 367.
    #include "B.hpp" class A{ public: A(int sz) : v(new B[sz]), sz_(sz) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; };
  • 368.
    #include "B.hpp" class A{ public: A(int sz) : v(new B[sz]), sz_(sz) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; Now this looks better! Is there anything else that needs to be improved? Perhaps some small stuff that I would like to mention...
  • 369.
    #include "B.hpp" classA { public: A(int sz) : v(new B[sz]), sz_(sz) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; Now this looks better! Is there anything else that needs to be improved? Perhaps some small stuff that I would like to mention... When I see bald pointers in C++ it is usually a bad sign. A lot of good C++ programmers tend to avoid using them like this. In this case of course, it looks like v is a candidate for being an STL vector or something like that.
  • 370.
    #include "B.hpp" class A { public: A(int sz) : v(new B[sz]), sz_(sz) {} ~A() { delete[] v; } // ... private: A(const A &); A & operator=(const A &); // ... B * v; int sz_; }; Now this looks better! Is there anything else that needs to be improved? Perhaps some small stuff that I would like to mention... When I see bald pointers in C++ it is usually a bad sign. A lot of good C++ programmers tend to avoid using them like this. In this case of course, it looks like v is a candidate for being an STL vector or something like that. You seem to use different naming conventions for private member variables, but as long as it is private stuff I think you can do whatever you want. But I guess either postfixing all member variables with _ is fine, so is prefixing with m_, but you should never just prefix with _ because you might stumble into reserved naming conventions for C, Posix and/or compilers.
  • 371.
    So what isit that she seems to understand better than most?
  • 372.
    So what isit that she seems to understand better than most? • the connection between C and C++
  • 373.
    So what isit that she seems to understand better than most? • the connection between C and C++ • some techniques for polymorphism
  • 374.
    So what isit that she seems to understand better than most? • the connection between C and C++ • some techniques for polymorphism • how to initialize objects properly
  • 375.
    So what isit that she seems to understand better than most? • the connection between C and C++ • some techniques for polymorphism • how to initialize objects properly • rule of three
  • 376.
    So what isit that she seems to understand better than most? • the connection between C and C++ • some techniques for polymorphism • how to initialize objects properly • rule of three • operator new[] and delete[]
  • 377.
    So what isit that she seems to understand better than most? • the connection between C and C++ • some techniques for polymorphism • how to initialize objects properly • rule of three • operator new[] and delete[] • common naming conventions
  • 378.
    We’d like toshare some things about: Object lifetime The rule of three The vtable
  • 379.
    proper object initialization assignmentis not the same as initialization struct A { A() { puts("A()"); } A(int v) { puts("A(int)"); } ~A() { puts("~A()"); } bad style }; A() A(int) struct X { ~A() X(int v) { a=v; } ~A() X(long v) : a(v) { } good style A a; }; A(int) ~A() int main() { puts("bad style"); { X slow(int(2)); } puts("good style"); { X fast(long(2)); } }
  • 380.
    object lifetime A basicprinciple of C++ is that the operations performed when an object’s life ends are the exact reverse of the operations performed when the object’s life starts. struct A int main() { { A() { puts("A()"); } C obj; ~A() { puts("~A()"); } } }; struct B A() { B() B() { puts("B()"); } ~B() { puts("~B()"); } ~B() }; ~A() struct C { A a; B b; };
  • 381.
    object lifetime A basicprinciple of C++ is that the operations performed when an object’s life ends are the exact reverse of the operations performed when the object’s life starts. struct A int main() { { A() : id(count++) A array[4]; { } printf("A(%d)n", id); } ~A() A(0) { printf("~A(%d)n", id); A(1) } A(2) int id; A(3) static int count; }; ~A(3) ~A(2) ~A(1) ~A(0)
  • 382.
    object lifetime A basic principle of C++ is that the operations performed when an object’s life ends are the exact reverse of the operations performed when the object’s life starts. int main() int main() struct A { { { A * array = new A[4]; A * array = new A[4]; A() : id(count++) delete[] array; delete array; { } } printf("A(%d)n", id); } ~A() A(0) A(0) { A(1) printf("~A(%d)n", id); A(1) } A(2) A(2) int id; A(3) static int count; A(3) }; ~A(0) ~A(3) ~A(2) ~A(1) ~A(0)
  • 383.
    The Rule ofThree If a class defines a copy constructor class wibble_ptr { public: wibble_ptr() : ptr(new wibble), count(new int(1)) { } wibble_ptr(const wibble_ptr & other) : ptr(other.ptr), count(other.count) { (*count)++; } . . . . . . . . . . private: wibble * ptr; int * count; };
  • 384.
    The Rule ofThree If a class defines a copy constructor, a copy assignment operator class wibble_ptr { public: wibble_ptr() : ptr(new wibble), count(new int(1)) { } . . . . wibble_ptr & operator=(const wibble_ptr & rhs) { wibble_ptr copy(rhs); swap(copy); return *this; } . . . . . private: wibble * ptr; int * count; };
  • 385.
    The Rule ofThree If a class defines a copy constructor, a copy assignment operator, or a destructor class wibble_ptr { public: wibble_ptr() : ptr(new wibble), count(new int(1)) { } . . . . . . . . . ~wibble_ptr() { if (--(*count) == 0) delete ptr; } . private: wibble * ptr; int * count; };
  • 386.
    The Rule ofThree If a class defines a copy constructor, a copy assignment operator, or a destructor, then it should define all three. class wibble_ptr { public: wibble_ptr() : ptr(new wibble), count(new int(1)) { } wibble_ptr(const wibble_ptr & other) : ptr(other.ptr), count(other.count) { (*count)++; } wibble_ptr & operator=(const wibble_ptr & rhs) { wibble_ptr copy(rhs); swap(copy); return *this; } ~wibble_ptr() { if (--(*count) == 0) delete ptr; } ... private: wibble * ptr; int * count; };
  • 387.
    The vtable struct base { 0 f base::f() {} virtual void f(); virtual void g(); vptr int a,b; }; a 1 g struct derived : base { b base base::g() {} virtual void g(); base object vtable virtual void h(); int c; }; void poly(base * ptr) { ptr->f(); vptr 0 f ptr->g(); derived::g() {} } a 1 g int main() { b 2 h poly(&base()); derived::h() {} poly(&derived()); } c derived derived object vtable
  • 388.
    The vtable base::f() {} struct base { void f(); virtual void g(); vptr 0 g base::g() {} int a,b; }; a base vtable struct derived : base { b virtual void g(); base object virtual void h(); int c; }; void poly(base * ptr) { derived::g() {} ptr->f(); ptr->g(); vptr 0 g } a 1 h int main() derived::h() {} { poly(&base()); b derived poly(&derived()); vtable } c derived object
  • 389.
    Would it beuseful if more of your colleagues have a deep understanding of the programming language they are using? We are not suggesting that all your C and C++ programmers in your organization need a deep understanding of the language. But you certainly need a critical mass of programmers that care about their profession and constantly keep updating themselves and always strive for a better understanding of their programming language.
  • 390.
    Let’s get backto our two developers...
  • 392.
    So what isthe biggest difference between these two developers?
  • 393.
    So what isthe biggest difference between these two developers? Current knowledge of the language?
  • 394.
    So what isthe biggest difference between these two developers? Current knowledge of the language? No!
  • 395.
    So what isthe biggest difference between these two developers? Current knowledge of the language? No! It is their attitude to learning!
  • 398.
    When was thelast time you did a course about programming?
  • 399.
    When was thelast time you did a course about programming? What do you mean? I learned programming at university and now I am learning by doing. What more do you need?
  • 400.
    When was thelast time you did a course about programming? What do you mean? I learned programming at university and now I am learning by doing. What more do you need? So what kinds of books are you reading?
  • 401.
    When was thelast time you did a course about programming? What do you mean? I learned programming at university and now I am learning by doing. What more do you need? So what kinds of books are you reading? Books? I don’t need books. I look up stuff on internet when I need it.
  • 402.
    When was thelast time you did a course about programming? What do you mean? I learned programming at university and now I am learning by doing. What more do you need? So what kinds of books are you reading? Books? I don’t need books. I look up stuff on internet when I need it. Do you discuss programming with your colleagues?
  • 403.
    When was thelast time you did a course about programming? What do you mean? I learned programming at university and now I am learning by doing. What more do you need? So what kinds of books are you reading? Books? I don’t need books. I look up stuff on internet when I need it. Do you discuss programming with your colleagues? They are all stupid, I have nothing to learn from them...
  • 405.
    You seem toknow a lot about C and C++? How come?
  • 406.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it.
  • 407.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it. I occasionally follow C and C++ discussions on stack overflow, comp.lang.c and comp.lang.c++
  • 408.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it. I occasionally follow C and C++ discussions on stack overflow, comp.lang.c and comp.lang.c++ I am a member of a local C and C++ Users Group, we have meetings once in a while
  • 409.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it. I occasionally follow C and C++ discussions on stack overflow, comp.lang.c and comp.lang.c++ I am a member of a local C and C++ Users Group, we have meetings once in a while I read books. Lots of books. Did you know that James Grenning just came out with a great book about Test-Driven Development in C?
  • 410.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it. I occasionally follow C and C++ discussions on stack overflow, comp.lang.c and comp.lang.c++ I am a member of a local C and C++ Users Group, we have meetings once in a while I read books. Lots of books. Did you know that James Grenning just came out with a great book about Test-Driven Development in C? I have to admit that I visit WG14 and WG21 once in a while
  • 411.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it. I occasionally follow C and C++ discussions on stack overflow, comp.lang.c and comp.lang.c++ I am a member of a local C and C++ Users Group, we have meetings once in a while I read books. Lots of books. Did you know that James Grenning just came out with a great book about Test-Driven Development in C? I have to admit that I visit WG14 and WG21 once in a while I am a member of ACCU, for those who care about professionalism in programming, I read Overload, C Vu and discussions on accu-general
  • 412.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it. I occasionally follow C and C++ discussions on stack overflow, comp.lang.c and comp.lang.c++ I am a member of a local C and C++ Users Group, we have meetings once in a while I read books. Lots of books. Did you know that James Grenning just came out with a great book about Test-Driven Development in C? I have to admit that I visit WG14 and WG21 once in a while I am a member of ACCU, for those who care about professionalism in programming, I read Overload, C Vu and discussions on accu-general And whenever I get a chance I attend classes teaching C and C++. It not always because I learn so much from the slides and the teacher, it is often through discussions with other learners that I expand my knowledge.
  • 413.
    You seem toknow a lot about C and C++? How come? I am learning new things every day, I really enjoy it. I occasionally follow C and C++ discussions on stack overflow, comp.lang.c and comp.lang.c++ I am a member of a local C and C++ Users Group, we have meetings once in a while I read books. Lots of books. Did you know that James Grenning just came out with a great book about Test-Driven Development in C? I have to admit that I visit WG14 and WG21 once in a while I am a member of ACCU, for those who care about professionalism in programming, I read Overload, C Vu and discussions on accu-general And whenever I get a chance I attend classes teaching C and C++. It not always because I learn so much from the slides and the teacher, it is often through discussions with other learners that I expand my knowledge. But perhaps the best source of knowledge is working closely with my colleagues and try to learn from them while contributing with my knowledge.
  • 414.
  • 415.
  • 416.
    Summary • compiler andlinker • declaration vs definition
  • 417.
    Summary • compiler andlinker • declaration vs definition • activation frame
  • 418.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments
  • 419.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment
  • 420.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points
  • 421.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order
  • 422.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified
  • 423.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified • optimization
  • 424.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified • optimization • something about C++
  • 425.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified • optimization • something about C++ • proper initialization of objects
  • 426.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified • optimization • something about C++ • proper initialization of objects • object lifetimes
  • 427.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified • optimization • something about C++ • proper initialization of objects • object lifetimes • vtables
  • 428.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified • optimization • something about C++ • proper initialization of objects • object lifetimes • vtables • rule of 3
  • 429.
    Summary • compiler andlinker • declaration vs definition • activation frame • memory segments • memory alignment • sequence points • evaluation order • undefined vs unspecified • optimization • something about C++ • proper initialization of objects • object lifetimes • vtables • rule of 3 • ... and something about attitude and professionalism
  • 430.
  • 432.
  • 433.
    Eh? Yes?
  • 434.
    Eh? Yes? I really love programming, but I realize now that perhaps I am not behaving as a true professional. Any advice on how to get started to get a deep knowledge of C and C++?
  • 435.
    Eh? Yes? I really love programming, but I realize now that perhaps I am not behaving as a true professional. Any advice on how to get started to get a deep knowledge of C and C++? First of all you must realize that programming is a continuous learning process, it does not matter how much you know, there is always much more to learn. The next thing to realize is that professional programming is first of all a team activity, you must work and develop together with your colleagues. Think about programming as a team sport, where nobody can win a whole match alone.
  • 436.
    Eh? Yes? I really love programming, but I realize now that perhaps I am not behaving as a true professional. Any advice on how to get started to get a deep knowledge of C and C++? First of all you must realize that programming is a continuous learning process, it does not matter how much you know, there is always much more to learn. The next thing to realize is that professional programming is first of all a team activity, you must work and develop together with your colleagues. Think about programming as a team sport, where nobody can win a whole match alone. Ok, I need to think about that...
  • 437.
    Eh? Yes? I really love programming, but I realize now that perhaps I am not behaving as a true professional. Any advice on how to get started to get a deep knowledge of C and C++? First of all you must realize that programming is a continuous learning process, it does not matter how much you know, there is always much more to learn. The next thing to realize is that professional programming is first of all a team activity, you must work and develop together with your colleagues. Think about programming as a team sport, where nobody can win a whole match alone. Ok, I need to think about that... Having said that. Make it a habit to once in a while take a look at the assembly output actually produced by snippets of C and C++. There are a lot of surprising things to discover. Use a debugger, step through code, study how memory is used and look at the instructions actually executed by the processor.
  • 439.
    Any books, sites,courses and conferences about C and C++ you would like to recommend?
  • 440.
    Any books, sites,courses and conferences about C and C++ you would like to recommend? To learn modern ways of developing software, I recommend “Test-Driven Development for Embedded C” by James Grenning. For deep C knowledge, Peter van der Linden wrote a book called “Expert C programming” two decades ago, but the content is still quite relevant. For C ++ I recommend you start with “Effective C++” by Scott Meyers and “C++ coding standards” by Herb Sutter and Andrei Alexandrescu.
  • 441.
    Any books, sites,courses and conferences about C and C++ you would like to recommend? To learn modern ways of developing software, I recommend “Test-Driven Development for Embedded C” by James Grenning. For deep C knowledge, Peter van der Linden wrote a book called “Expert C programming” two decades ago, but the content is still quite relevant. For C ++ I recommend you start with “Effective C++” by Scott Meyers and “C++ coding standards” by Herb Sutter and Andrei Alexandrescu. Also, whenever you get a chance to go to a course about C and C++, do so. If your attitude is right, there is just so much to learn from both the instructor and the other students at the course.
  • 442.
    Any books, sites,courses and conferences about C and C++ you would like to recommend? To learn modern ways of developing software, I recommend “Test-Driven Development for Embedded C” by James Grenning. For deep C knowledge, Peter van der Linden wrote a book called “Expert C programming” two decades ago, but the content is still quite relevant. For C ++ I recommend you start with “Effective C++” by Scott Meyers and “C++ coding standards” by Herb Sutter and Andrei Alexandrescu. Also, whenever you get a chance to go to a course about C and C++, do so. If your attitude is right, there is just so much to learn from both the instructor and the other students at the course. And finally, I would recommend that you get yourself involved in user groups and communities for programmers. In particular I would recommend the ACCU (accu.org), they are very much focused on C and C++ programming. Did you know they host a conference in Oxford every spring where professional programmers from all around the world meet to discuss programming for a week? Perhaps I see you there in April next year?
  • 443.
    Any books, sites,courses and conferences about C and C++ you would like to recommend? To learn modern ways of developing software, I recommend “Test-Driven Development for Embedded C” by James Grenning. For deep C knowledge, Peter van der Linden wrote a book called “Expert C programming” two decades ago, but the content is still quite relevant. For C ++ I recommend you start with “Effective C++” by Scott Meyers and “C++ coding standards” by Herb Sutter and Andrei Alexandrescu. Also, whenever you get a chance to go to a course about C and C++, do so. If your attitude is right, there is just so much to learn from both the instructor and the other students at the course. And finally, I would recommend that you get yourself involved in user groups and communities for programmers. In particular I would recommend the ACCU (accu.org), they are very much focused on C and C++ programming. Did you know they host a conference in Oxford every spring where professional programmers from all around the world meet to discuss programming for a week? Perhaps I see you there in April next year? Thanks!
  • 444.
    Any books, sites,courses and conferences about C and C++ you would like to recommend? To learn modern ways of developing software, I recommend “Test-Driven Development for Embedded C” by James Grenning. For deep C knowledge, Peter van der Linden wrote a book called “Expert C programming” two decades ago, but the content is still quite relevant. For C ++ I recommend you start with “Effective C++” by Scott Meyers and “C++ coding standards” by Herb Sutter and Andrei Alexandrescu. Also, whenever you get a chance to go to a course about C and C++, do so. If your attitude is right, there is just so much to learn from both the instructor and the other students at the course. And finally, I would recommend that you get yourself involved in user groups and communities for programmers. In particular I would recommend the ACCU (accu.org), they are very much focused on C and C++ programming. Did you know they host a conference in Oxford every spring where professional programmers from all around the world meet to discuss programming for a week? Perhaps I see you there in April next year? Thanks! Good luck!
  • 445.