[Courses] C Programming For Absolute Beginners, Lesson 1: Setting Up, First Program

Jacinta Richardson jarich at perltraining.com.au
Mon Feb 6 00:45:58 UTC 2012


On 06/02/12 10:49, jim wrote:
>      Note that the #include preprocessor directive seems to take
> <stdio.h>
> as an argument.
>      The<  >  angle bracket characters have a special meaning:
> /usr/include/
>

The angle brackets refer to the system directories, which might not always be 
/usr/include but could even be /opt/usr/include etc.

>      The #include preprocessor directive opens the file and pastes
> its entire contents into the C program at that location. This
> means what the compiler compiles is not only the code but all of
> the code in the stdio.h file, yes?
stdio.h is a *header* file.  This means it's actually just the headers for an 
underlying pre-compiled C library.  So when we include the header file, we 
compile links to the existing C library.  So when we compile our program we 
compile all of our code and all the headers they include and get all the links 
to the functions defined in those headers etc.  Note that stdio.h also includes 
other headers, which may also include other header files recursively.  (There 
are ways of preventing loops that I imagine we'll cover much, much, much later).

Note that this linking to existing pre-compiled C libraries makes our program 
much smaller than if we included everything in it directly, but it also makes 
the compiled code non-portable.  You can write, compile and execute the code 
Carla's given us, on Windows and *nix without issue; but you cannot take the 
Windows executable and run it on *nix or visa versa.  In fact, as you may 
eventually discover, you can't take a *nix executable and assume it'll run on a 
different flavour of *nix.  It used to be that you couldn't even necessarily run 
it on different versions of the same *nix flavour, although I believe that 
that's gotten a lot better over the last decade and a half (ymmv).

Later I expect Carla will talk about creating our own header files and linking 
shared object files but right now that's way out of scope.

>      How does one "look up the spec" for stdio.h?
>

man stdio

>      A look at my working directory:
> ls -l
> -rwxr-xr-x 1 jim jim 7180 2012-02-05 15:18 welcome
> -rw-r--r-- 1 jim jim  108 2012-02-05 15:18 welcome.c
>
> ---------------------^^^^---------------------------
>
>      The welcome.c source code is 108 bytes, but the welcome
> binary program is 7180 bytes.
>      Wait a minute. The stdio.h file is 31KB, a lot bigger.
> What's going on?
>

The stdio.h has a lot of definitions, comments, whitespace etc in it that pretty 
much vanishes when we compile it.  Thus your executable is bigger than your 
source file because it does contain the information from stdio.h, but it loses 
information such as variable names, function names, comments, #defines etc.

> $ strings welcome
> strings lchix
> /lib/ld-linux.so.2
> __gmon_start__
> libc.so.6
> _IO_stdin_used
> puts
> getchar
> __libc_start_main
> GLIBC_2.0
> PTRh0
> [^_]
> Hello, and welcome to the Beginning C Course!
>
>      There are not many strings in the welcome binary file.
>      How'd the welcome binary file get to be over 7KB but not
> have hardly any of the stdio.h file contents?

Because large parts of the binary bits are links to the precompiled libraries.

>      And what's up with the Martian (like [^_] and /lib/ld-linux.so.2
> and __gmon_start__ and _IO_stdin_used and PTRh0 and so on)?
>

strings doesn't exist to make compiled code easier for humans to read.  It 
exists to pull out sequences of two or more ascii characters in a row.  I'm 
actually surprised there isn't more Martian. ;)  ([^_] and PTRh0 are Martian and 
can be ignored)

/lib/ld-linux.so.2 is a shared object file.  It's what is going to be used to 
help your executable find any other shared object files it needs.  More here: 
http://www.cs.virginia.edu/~dww4s/articles/ld_linux.html

__gmon_start__ is an anchor to where the relevant stuff for <sys/gmon.h> starts.

  _IO_stdin_used is an internal symbol used by libio.h (which stdio.h 
includes).  I'm guessing this is set because our code uses getchar which gets a 
character from STDIN.

>      How come one of strings is
> puts?

man -s3 puts

printf is a very fancy way of printing characters to the screen.  The "f" at the 
end of the function name tells us that it can take a format string so we could 
write:

     printf("%-50s", "Hello World!");

if we wanted to.  With straightforward strings like this that have no variables 
that need to be worked out at run time, we can convert the (more expensive) call 
to printf(ormat) to a simple call to puts(tring) to output it to STDOUT.

>      I used the printf() function, not the puts() function.

As above.

>      I'm betting that libc.so.6 stores the binary code for printf
> and puts and getchar on other stdio.h functions, yes?

Probably, but you don't need to care about those details. You need only to 
include the stdio.h file and whichever precompiled library that currently houses 
the files you need is the one that will be used.

>      What's __libc_start_main about? And GLIBC_2.0 ?
>

GLIBC_2.0 is the GNU Shared Lib C library 2.0.

__libc_start_main is another anchor.  Presumably to the start of the compiled 
links to libc.

>      And how come the "Hello, and welcome tothe Beginning C Course!"
> is on the very bottom?
>

Things get compiled in order.  All the stuff above was related to your inclusion 
of stdio.  Everything after that is your code.

All the best,

     J



More information about the Courses mailing list