| Goals for this chapter: |
|
In this chapter we will the standard C Library, "libc.a" and show
ho to use it. However, is fundamental to know and understand the C compiler,
as a development tool, as well how is adopted by the diferent Linux distro,
to avoid strange results.
We also will introduce how to use 'others' common development tools like "nm", "strings", "objdump", "objcopy", "strip", "size".
The C Language haves its Standard C Library, called "libc.a", where are located the most used function for string, Basic I/O, Mathematical and other similar essential tasks.
The libc.a interact with the following include includes files: stdio.h,
string.h,
math.h,
stdlib.h,
unistd.h,
signal.h,
pwd.h,
sys/stat.h.
and others includes files present in "/usr/include".
Here we cover how to use these function is our programs.
To be a programmer you need to have the ideas and projects, knows
the language and the libraries that you will use. A clear knowledge about
all development tools is also necessary.
From the first days of OpenSource (1989), Richard Stallman and its Free Software Foundation offers at no cost the most incredible and better compiler ever written. The 'GCC', the GNU C Compiler.
Actually the tarball (the downloadable version in tar format) is available at: ftp://gcc.gnu.org/
The GCC Website is http://gcc.gnu.org/.
The C Compiler is one of the most fundamental component in any Operating System, specially in Linux OS. Almost everything is compiled with the gcc or the C++ companion: "g++". All the Basic Utilities, "awk", "sed" and others are written in C. The X Window System and almost all the Windows Managers including the OpenMotif GUI is written in C. Also, Gtk is written in C. Modern interfaces as Qt and KDE are written in C++.
For this reason is fundamental to know and understand very well, how
to use C functions.
After the RedHat Cygnus acquisition, RedHat start to develop its
own C Compiler, "2.96". As explains Mark
Mitchell, GCC Release Manager the release of this version (not in accord
with GNU GCC numbers) was a real problem, also because the generated binaries
from C++ code, are not compatible with its equivalent GNU compilers.
The RPM packages for the GCC Compiler in 7.2 are the following:
[root@ftosx1 RPMS]# ls -al gcc-*
-rw-r--r-- 2 root
root 2987778 Sep 7 18:06 gcc-2.96-98.i386.rpm
-rw-r--r-- 2 root
root 1730815 Sep 7 18:06 gcc-c++-2.96-98.i386.rpm
-rw-r--r-- 2 root
root 1303223 Sep 7 18:06 gcc-chill-2.96-98.i386.rpm
-rw-r--r-- 2 root
root 1758083 Sep 7 18:06 gcc-g77-2.96-98.i386.rpm
-rw-r--r-- 2 root
root 1333136 Sep 7 18:06 gcc-java-2.96-98.i386.rpm
-rw-r--r-- 2 root
root 1208700 Sep 7 18:06 gcc-objc-2.96-98.i386.rpm
[root@ftosx1 RPMS]#
Also is included the C Pre-Processor: "cpp"
[root@ftosx1 RPMS]# ls -al cpp*
-rw-r--r-- 3 root
root 194154 Sep 7 18:06 cpp-2.96-98.i386.rpm
and also the libstdc++*, the GNU Standard C++ an ongoing project to implement the ISO 14882 Standard C++ library.
[root@ftosx1 RPMS]# ls -al libstdc++*
-rw-r--r-- 3 root
root 164400 Sep 7 18:06 libstdc++-2.96-98.i386.rpm
-rw-r--r-- 2 root
root 357742 Sep 7 18:06 libstdc++-devel-2.96-98.i386.rpm
Therefore from the gcc-X.src are build 9 packages that regards the GNU Compilers; the C Lib belong to the "glibc" RPM Package, we will back on this later in this chapter. Both, the "GCC" and GLIBC and the LIBSTDC++ are the three components necessary to develop programs in C and C++, on Linux systems.
Now, is very important to remark that the 2.96.X Compiler is not a GNU project but a RedHat 'gaffe' compiler.
This compiler is a 'gaffe' for the following reasons:
What is the sense to create a 'different' compiler with new parameters while 'everyone' uses the acepted standard gcc with its 'standard' parameters ?
Other distro adopt the standard GNU C Compiler releases ... and follows the normal trend. For example, we have:
" - Make sure you have gcc 2.95.3 available. gcc 2.91.66
(egcs-1.1.2) may
also work but is not as safe, and *gcc 2.7.2.3
is no longer supported*.
Also remember to upgrade your binutils package
(for as/ld/nm and company)
if necessary. For more information, refer to ./Documentation/Changes.
What is the better choice for 'old' RedHat users to maintain compatibility with the latest version. FTOSX 2002, adopt the GNU GCC 3.1.
However, adopt and use the RedHat "glibc" open a compatibity for common
RedHat/Cygnus. In other words, not the compiler but, yes for the glibc
compiler. Other discussion in this sense will simply make a final decision
for one or other distro.
With the release of GNU GCC 3.1, the GCC team, complete an important taks in GCC history with a complete C++ ABI implementation.
In fact, as explained in the LSB 1.1, the C++ is immature and therefore does not belong to the LSB.

The immaturity regards the ABI (Application Binary Interface), for C++. This ABI does not have a clear form. The information about this matter is available at:
This company: codesourcey haves the role to certify and test the GNU GCC Compiler.
Because neither GCC 3.1 is 100% complaint, in LSB 1.2, the Mapping continues to be immature. However, GNU C++ 3.1 open the trend to solve this matter. The GNU GCC 3.1 makes a difference between past and new innovations.
The previous "chil" support had been removed. Actually the GNU GCC 3.1, supports: C, C++, Fortran, Java and Ada languages.
Here we list the RPM packages:
One of the first steps that a C Compiler follows to generate a binary
from the C source (written in Plain ASCII), is the pre-processor.
The preprocessor, the 'cpp' evaluate and explode all the #includes and #define.
Consider the following source:
[root@ftosx1 Chap3]# more stat.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MIN_ARGUMENTS 2
main (int argc, char
** argv)
{
int i;
struct
stat mybuf;
if
(argc < 2)
fprintf (stderr, "Use: %sfile(s)\n",
argv[0]);
else
for
( i = 1; i < argc; ++i)
if (stat (argv[1],
&mybuf))
fprintf (stderr, "%s:
can't
stat %s\n", argv[0],
argv[1]);
else
printf ("%03o\t%s\n", (long)
(mybuf.st_mode & 0xffff) , argv[i]);
}
[root@ftosx1 Chap3]#
Note the lines #include and #define.
As introduced in the previous Chapter, the #define represent a macro that may be a function or a number, while the include is a set of declarations.
The 'cpp' expand all these defines and includes in a very large source with all the expansions.
[root@ftosx1 Chap3]# cpp stat.c > stat.cpp
[root@ftosx1 Chap3]# head !$
head stat.cpp
# 1 "stat.c"
# 1 "/usr/include/stdio.h" 1 3
...
The expanded source have a size equivalent to more than 20 times the original ".c" source. Please note,
-rw-r--r-- 1 root root
443 Mar 4 10:17 stat.c
-rw-r--r-- 1 root
root 27216 Mar 4 10:27
stat.cpp
In this case the size of the expanded source is 61 time the original C.
The "cpp" includes some options to includes also comments in the define explosion
For example we have:
-C: Do not discard comments
-P: Inhibit generation of #-lines
and
-traditional: to imitate the old C
In the same mode that the RPM Packages includes the compiler, the
C Library belong to another package: "glibc".
In fact, running the command:
[root@ftosx1 root]# rpm -qf /usr/lib/libc.a
glibc-devel-2.2.90-8
[root@ftosx1 root]#
We note that the library belong to the glibc-devel. The complete set of packages generated from the "glibc.X.src" is the following:
[root@ftosx1 root]# nm /usr/lib/libc.a | more
init-first.o:
000001a3 t Letext
U __close
U __environ
U __fpu_control
U __init_misc
00000004 C __libc_argc
00000004 C __libc_argv
U __libc_fatal
0000017c T __libc_init_first
...
For example, we can list all the 'printf' functions:
[root@ftosx1 root]# nm /usr/lib/libc.a | grep printf.o
vfprintf.o:
vprintf.o:
reg-printf.o:
fprintf.o:
printf.o:
snprintf.o:
sprintf.o:
asprintf.o:
dprintf.o:
vfwprintf.o:
iosprintf.o:
iovsprintf.o:
fwprintf.o:
swprintf.o:
vwprintf.o:
wprintf.o:
vswprintf.o:
vasprintf.o:
iovdprintf.o:
vsnprintf.o:
obprintf.o:
[root@ftosx1 root]#
Now, we have a better clear vision about the compiler and its components, we will move to the programming part.
We will introduce the C Library functions in accord to its role,
organized in by includes.
In order of importance we can list the following includes.
Of course there are others functions and other includes files all present in the tree which root directory is "/usr/include"Therefore, functions to handle files, or to print data on files are present here.
We have a quick list.
Please compile the source:
[root@ftosx1 Chap3]# more buffsiz.c
#include <stdio.h>
main()
{
printf ("%d\n", BUFSIZ);
}
[root@ftosx1 Chap3]#
And the BUFSIZ is:
[root@ftosx1 Chap3]# ./buffsiz
8192
[root@ftosx1 Chap3]#
A normal mode to use these functions is the following.
#include <stdio.h>
main(argc, argv)
int argc;
char **argv;
{
int c;
FILE *from, *to;
/*
* Check our arguments.
*/
if (argc != 3) {
fprintf(stderr, "Usage:
%s from-file to-file\n", *argv);
exit(1);
}
/*
* Open the from-file for reading.
*/
if ((from = fopen(argv[1], "r")) == NULL)
{
perror(argv[1]);
exit(1);
}
/*
* Open the to-file for appending.
If to-file does
* not exist, fopen will create it.
*/
if ((to = fopen(argv[2], "a")) == NULL) {
perror(argv[2]);
exit(1);
}
/*
* Now read characters from from-file
until we
* hit end-of-file, and put them onto
to-file.
*/
while ((c = getc(from)) != EOF)
putc(c, to);
/*
* Now close the files.
*/
fclose(from);
fclose(to);
exit(0);
}
[root@ftosx1 My]#
To compile this program we need to run the command:
[root@ftosx1 My]# gcc 2.1.c -o mycopy
Note that nothing else is necessary. Neither special includes flags like "-I" (to add new includes), neither "-L/usr/lib/" (to add more libraries) are needed.
Note also the "-o" that is the flag to compile the program and generate the binary.
To run this binary that does a simple copy we run the command:
[root@ftosx1 My]# ./mycopy /etc/passwd ./mypasswd
[root@ftosx1 My]# diff /etc/passwd ./mypasswd
[root@ftosx1 My]#
Note that we add the "." before the binary because (generally) it does not belong to the PATH enviroment.
In the program we apply a very elementary approach.
[root@ftosx1 Chap3]# more sizeof_file.c
#include <stdio.h>
main ()
{
FILE * myfile;
printf ("%d\n", sizeof (myfile));
}
[root@ftosx1 Chap3]#
Compiling this source we will get the following output.
[root@ftosx1 Chap3]# gcc sizeof_file.c -o sizeof_file
[root@ftosx1 Chap3]# ./sizeof_file
4
[root@ftosx1 Chap3]#
Therefore the sizeof of the FILE type is 4 bytes.
The FILE type is one of the common structures in C language. While the FILE type is defined with a typedef in its stdio.h:
typedef struct _IO_FILE FILE;
we will have the definition inside the file "/usr/include/libio.h"
struct _IO_FILE {
int _flags; /* High-order
word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf
protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end
fields directly. */
char* _IO_read_ptr; /* Current read pointer
*/
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area.
*/
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area.
*/
char* _IO_buf_end; /* End of reserve
area. */
/* The following fields are used to support backing up
and undo. */
char *_IO_save_base; /* Pointer to start of non-current
get area. */
char *_IO_backup_base; /* Pointer to first valid
character of backup area */
char *_IO_save_end; /* Pointer to end of non-current
get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
int _blksize;
_IO_off_t _old_offset; /* This used to be _offset but
it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
Is very normal that a "#includes" file includes other #include files. The reason for this is for semplicity ... so we the programer ... need to include a single "include" file: "#include <stdio.h>"
The FILE type is also used for directories.
We list here a small sample about that.
[root@ftosx1 My]# more 4.1.c
#include <sys/types.h>
#include <sys/dir.h>
#include <stdio.h>
main()
{
FILE *fp;
struct direct dir;
int n;
if ((fp = fopen(".", "r")) == NULL) {
perror("current directory");
exit(1);
}
/*
* Read directory
entries. Since we're reading
* entries one
at a time, we use the fread routine,
* which buffers
them internally. Don't use the
* low-level
read to do things this way, since
* reading very
small quantities of data (16 bytes)
* at a time
is very inefficient.
*/
while ((n = fread(&dir, sizeof(dir),
1, fp)) > 0) {
/*
* Skip removed
files.
*/
if (dir.d_ino ==
0)
continue;
/*
* Make sure
we print no more than ... 30
* characters.
*/
printf("%.*s\n",
30, dir.d_name);
}
fclose(fp);
exit(0);
}
[root@ftosx1 My]#
[root@ftosx1 root]# ls -al /etc/passwd
-rw-r--r-- 1 root
root 1666 Jul 4 15:23
/etc/passwd
[root@ftosx1 root]#
The C structure for this is the stat structure.
struct stat
{
__dev_t st_dev;
/* Device. */
unsigned short int __pad1;
#ifndef __USE_FILE_OFFSET64
__ino_t st_ino;
/* File serial number. */
#else
__ino_t __st_ino;
/* 32bit file serial number. */
#endif
__mode_t st_mode;
/* File mode. */
__nlink_t st_nlink;
/* Link count. */
__uid_t st_uid;
/* User ID of the file's owner. */
__gid_t st_gid;
/* Group ID of the file's group.*/
__dev_t st_rdev;
/* Device number, if device. */
unsigned short int __pad2;
#ifndef __USE_FILE_OFFSET64
__off_t st_size;
/* Size of file, in bytes. */
#else
__off64_t st_size;
/* Size of file, in bytes. */
#endif
__blksize_t st_blksize;
/* Optimal block size for I/O. */
#ifndef __USE_FILE_OFFSET64
__blkcnt_t st_blocks;
/* Number 512-byte blocks allocated. */
#else
__blkcnt64_t st_blocks;
/* Number 512-byte blocks allocated. */
#endif
__time_t st_atime;
/* Time of last access. */
unsigned long int __unused1;
__time_t st_mtime;
/* Time of last modification. */
unsigned long int __unused2;
__time_t st_ctime;
/* Time of last status change. */
unsigned long int __unused3;
#ifndef __USE_FILE_OFFSET64
unsigned long int __unused4;
unsigned long int __unused5;
#else
__ino64_t st_ino;
/* File serial number. */
#endif
};
Notet that here are listed the size (st_size), as well the inode (st_ino).
A smart user may ask, what are "__ino_t" types? These types are the type used by
May be that this type is a complex "define" using standard types, or a struct or a simple typedef.
In this case is a simple typedef for __u_long that is equivalent to unsigned long.
types.h:typedef __u_long __ino_t;
/* Type of file serial numbers. */
However, may happen almost everyting. Note for example the use of "ifndef" inside the simple structure declaration. This is the standard mode to use the code (C or C++).
Now, we will write a simple program that will list the size and inode info for the local files.
[root@ftosx1 Chap3]# more stat.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MIN_ARGUMENTS 2
main (int argc, char ** argv)
{
int i;
struct stat mybuf;
if (argc < MIN_ARGUMENTS
)
fprintf (stderr, "Use: %s file(s)\n", argv[0]);
else
for ( i = 1; i < argc; ++i)
if (stat (argv[1], &mybuf))
fprintf (stderr, "%s: can't stat %s\n", argv[0], argv[1]);
else
printf ("%d\t%03o\t%s\n", (long) (mybuf.st_ino), (long) (mybuf.st_mode
& 0xffff) , argv[i]);
}
[root@ftosx1 Chap3]#
We will run the commands to compile.
[root@ftosx1 Chap3]# gcc stat.c -o stat
To get the info we will check before with our "ls" (listing programs) and add the parameter for inode.
[root@ftosx1 Chap3]# ls -ali stat.c
239985 -rw-r--r-- 1 root
root 470 Jul
5 13:20 stat.c
[root@ftosx1 Chap3]#
[root@ftosx1 Chap3]# ./stat stat.c
239985 100644 stat.c
[root@ftosx1 Chap3]#
Note that the file size is the same while the mode is 644. The number '1' means archive.
We can also apply this to the directory:
[root@ftosx1 Chap3]# ./stat ..
239919 40755 ..
[root@ftosx1 Chap3]#
The number '4' means directory. The 0755 are the actual properties for this directory.
Other info will be available in the same mode.
The information for the "/etc/passwd" file is handled by the includes file "pwd.h"; not Print Working Directory.
The structure is the following.
/* The passwd structure. */
struct passwd
{
char *pw_name;
/* Username. */
char *pw_passwd; /* Password.
*/
__uid_t pw_uid; /*
User ID. */
__gid_t pw_gid; /*
Group ID. */
char *pw_gecos; /*
Real name. */
char *pw_dir;
/* Home directory. */
char *pw_shell; /*
Shell program. */
};
Now, we will the standard C function getpwnam to browse the entire passwd entry.
Our first program read the information for the user "root".
#include <stdio.h>
#include <pwd.h>
#define NAMELEN 8
main()
{
FILE *fp;
struct passwd *p;
char tmp[NAMELEN+1];
struct passwd *getpwnam();
strcpy(tmp, "root");
if ((p = getpwnam(tmp)) == NULL)
exit (1);
printf("%-30.30s %s %d %d %s %s %s\n", p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
exit(0);
}
Compiling ...
[root@ftosx1 My]# gcc mypasswd.c -o mypasswd
Before to run we will list the "root" entry.
[root@ftosx1 My]# more /etc/passwd | grep root:x
root:x:0:0:root:/root:/bin/bash
[root@ftosx1 My]#
Now, we will print the results
[root@ftosx1 My]# ./mypasswd
root
x 0 0 root /root /bin/bash
[root@ftosx1 My]#
We can update the program using the function:
#include <stdio.h>
#include <pwd.h>
#define NAMELEN 8
main()
{
FILE *fp;
struct passwd *p;
char tmp[NAMELEN+1];
struct passwd *getpwnam();
char *username, *getlogin();
/*
* Get the user's name.
*/
if ((username = getlogin()) == NULL) {
fprintf(stderr, "Who
are you?\n");
exit(1);
}
strncpy(tmp, username, NAMELEN);
if ((p = getpwnam(tmp)) == NULL)
exit (1);
printf("%-30.30s %s %d %d %s %s %s\n", p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
exit(0);
}
This function gets the user using the program, and apply the getpwnam routine.
[root@ftosx1 My]# ./mypasswd2
root
x 0 0 root /root /bin/bash
[root@ftosx1 My]#
We have:
bool n(void* s) {
return ((*(long*)s-0x01010101)&~(*(long*)s)&0x80808080);
}
int f(char* p) {
int r = 0;
while(!n(p))r+=4,p+=4;
while(*p++)++r;
return r;
}
Now, we will develop some special examples to use this functions:
The use of these function is quite simple or elementary.
For example, in the previous program we use the
char tmp[NAMELEN+1];
strncpy(tmp, username, NAMELEN);
Where username return from a function and is a char pointer. There are no secrets at all. However is important to remember that a string may be understood as vector of characters, that must have a well know end.
To end a string is sufficient to add a char NULL, '\0'.
That's all. If you try to use a memoey position out of the range, for example the string is long 45 characters, and you try to write (also to access) a position like 76, the program will stop and generate a SEGV.
Here we will introduce a pretty and simple example about strtok, that is probably the most not common function. The other functions are very easy to use.
The example is quit simple.
We have a string ... and will split in tokens using an allocated char *.
[root@ftosx1 Chap3]# more strtok.c
#include <stdio.h>
#include <malloc.h>
main ()
{
char line[50], * tmp;
strcpy (line, "John Smith :1620 26th Street - Santa Monica:4257:1:18:M");
puts (line);
strtok (line, ":");
puts (line);
tmp = calloc (50, sizeof(char));
tmp = (char *) strtok
(NULL, ":");
puts (tmp);
tmp = (char *) strtok
(NULL, ":");
puts (tmp);
tmp = (char *) strtok
(NULL, ":");
puts (tmp);
tmp = (char *) strtok
(NULL, ":");
puts (tmp);
}
[root@ftosx1 Chap3]#
Compiling and executing we will have:
[root@ftosx1 Chap3]# gcc strtok.c -o strtok
[root@ftosx1 Chap3]#
[root@ftosx1 Chap3]# ./strtok
John Smith :1620 26th Street - Santa
Monica:4257:1:18:M
John Smith
1620 26th Street - Santa Monica
4257
1
18
[root@ftosx1 Chap3]#
We list here these functions:
We list here the functions:
Example about this functions are real elementary and will no comment here. However, we prefer to introduce the includes <stdarg.h>. In this file are included the declaration.
va_list argument_list;
This is the mode used by functions like printf, scanf, and others to handle a large list of arguments, basically unlimited, or un-know.
Signals are a very important matter on UNIX system, and working with sleep and shell programming.
Here we will simply list the signals.
The signals are the following:
/* Signals. */
#define SIGHUP
1 /* Hangup (POSIX). */
#define SIGINT
2 /* Interrupt (ANSI). */
#define SIGQUIT
3 /* Quit (POSIX). */
#define SIGILL
4 /* Illegal instruction (ANSI).
*/
#define SIGTRAP
5 /* Trace trap (POSIX). */
#define SIGABRT
6 /* Abort (ANSI). */
#define SIGIOT
6 /* IOT trap (4.2 BSD). */
#define SIGBUS
7 /* BUS error (4.2 BSD). */
#define SIGFPE
8 /* Floating-point exception (ANSI).
*/
#define SIGKILL
9 /* Kill, unblockable (POSIX).
*/
#define SIGUSR1
10 /* User-defined signal 1 (POSIX).
*/
#define SIGSEGV
11 /* Segmentation violation (ANSI).
*/
#define SIGUSR2
12 /* User-defined signal 2 (POSIX). */
#define SIGPIPE
13 /* Broken pipe (POSIX). */
#define SIGALRM
14 /* Alarm clock (POSIX). */
#define SIGTERM
15 /* Termination (ANSI). */
#define SIGSTKFLT 16
/* Stack fault. */
#define SIGCLD
SIGCHLD /* Same as SIGCHLD (System V). */
#define SIGCHLD
17 /* Child status has changed (POSIX).
*/
#define SIGCONT
18 /* Continue (POSIX). */
#define SIGSTOP
19 /* Stop, unblockable (POSIX). */
#define SIGTSTP
20 /* Keyboard stop (POSIX). */
#define SIGTTIN
21 /* Background read from tty (POSIX).
*/
#define SIGTTOU
22 /* Background write to tty (POSIX).
*/
#define SIGURG
23 /* Urgent condition on socket (4.2 BSD).
*/
#define SIGXCPU
24 /* CPU limit exceeded (4.2 BSD).
*/
#define SIGXFSZ
25 /* File size limit exceeded (4.2 BSD).
*/
#define SIGVTALRM 26
/* Virtual alarm clock (4.2 BSD). */
#define SIGPROF
27 /* Profiling alarm clock (4.2 BSD).
*/
#define SIGWINCH 28
/* Window size change (4.3 BSD, Sun). */
#define SIGPOLL
SIGIO /* Pollable event occurred (System V). */
#define SIGIO
29 /* I/O now possible (4.2 BSD). */
#define SIGPWR
30 /* Power failure restart (System V).
*/
#define SIGSYS
31 /* Bad system call. */
#define SIGUNUSED 31
A complete coverage is offered in Chapter P8. Process management
The tm function is included in the file: time.h
struct tm
{
int tm_sec;
/* Seconds. [0-60] (1 leap second) */
int tm_min;
/* Minutes. [0-59] */
int tm_hour;
/* Hours. [0-23] */
int tm_mday;
/* Day. [1-31] */
int tm_mon;
/* Month. [0-11] */
int tm_year;
/* Year - 1900. */
int tm_wday;
/* Day of week. [0-6] */
int tm_yday;
/* Days in year.[0-365] */
int tm_isdst;
/* DST. [-1/0/1]*/
# ifdef __USE_BSD
long int tm_gmtoff;
/* Seconds east of UTC. */
__const char *tm_zone;
/* Timezone abbreviation. */
# else
long int __tm_gmtoff;
/* Seconds east of UTC. */
__const char *__tm_zone;
/* Timezone abbreviation. */
# endif
};
Now we will run a program that do a countdown using the time function.
[root@ftosx1 My]# more 5.3.c
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
main()
{
int n, nfds;
char buf[32];
fd_set readfds;
struct timeval tv;
/*
* We will be reading from standard
input (file
* descriptor 0), so we want to know
when the
* user has typed something.
*/
FD_ZERO(&readfds);
FD_SET(0, &readfds);
/*
* Set the timeout for 15 seconds.
*/
tv.tv_sec = 15;
tv.tv_usec = 0;
/*
* Prompt for input.
*/
printf("Type a word; if you don't in 15 ");
printf("seconds I'll use \"WORD\": ");
fflush(stdout);
/*
* Now call select. We pass NULL
for
* writefds and exceptfds, since we
* aren't interested in them.
*/
nfds = select(1, &readfds, NULL, NULL,
&tv);
/*
* Now we check the results. If
nfds is zero,
* then we timed out, and should assume
the
* default. Otherwise, if file
descriptor 0
* is set in readfds, that means that
it is
* ready to be read, and we can read
something
* from it.
*/
if (nfds == 0) {
strcpy(buf, "WORD");
}
else {
if (FD_ISSET(0, &readfds))
{
n = read(0, buf, sizeof(buf));
buf[n-1] = '\0';
}
}
printf("\nThe word is: %s\n", buf);
exit(0);
}
[root@ftosx1 My]#
Running we will simply have:
[root@ftosx1 My]# ./mytime
Type a word; if you don't in 15 seconds I'll use "WORD": Linux
The word is: Linux
[root@ftosx1 My]# ./mytime
Type a word; if you don't in 15 seconds I'll use "WORD":
The word is: WORD
[root@ftosx1 My]#
As you probably knows, the PI number 3.141516 is an irrational number. This means that will be impossible to print the exact number. We need to cut it and write an approximation, like the previous.
In particular these approximation for PI, E and other constants are present in the file: math.h.
/* Some useful constants. */
#if defined __USE_BSD || defined __USE_XOPEN
# define M_E 2.7182818284590452354
/* e */
# define M_LOG2E 1.4426950408889634074
/* log_2 e */
# define M_LOG10E 0.43429448190325182765 /*
log_10 e */
# define M_LN2 0.69314718055994530942
/* log_e 2 */
# define M_LN10 2.30258509299404568402
/* log_e 10 */
# define M_PI 3.14159265358979323846
/* pi */
# define M_PI_2 1.57079632679489661923
/* pi/2 */
# define M_PI_4 0.78539816339744830962
/* pi/4 */
# define M_1_PI 0.31830988618379067154
/* 1/pi */
# define M_2_PI 0.63661977236758134308
/* 2/pi */
# define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi)
*/
# define M_SQRT2 1.41421356237309504880
/* sqrt(2) */
# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2)
*/
#endif
However, this section does not regards, limits in Mathematical or approximation, but just for C types.
The include file: limits.h, includes these limits.
We can note the following declarations.
/* Number of bits in a `char'. */
# define CHAR_BIT 8
/* Minimum and maximum values a `signed char' can hold.
*/
# define SCHAR_MIN (-128)
# define SCHAR_MAX 127
/* Maximum value an `unsigned char' can hold. (Minimum
is 0.) */
# define UCHAR_MAX 255
/* Minimum and maximum values a `char' can hold. */
# ifdef __CHAR_UNSIGNED__
# define CHAR_MIN 0
# define CHAR_MAX UCHAR_MAX
# else
# define CHAR_MIN SCHAR_MIN
# define CHAR_MAX SCHAR_MAX
# endif
/* Minimum and maximum values a `signed short int' can hold.
*/
# define SHRT_MIN (-32768)
# define SHRT_MAX 32767
/* Maximum value an `unsigned short int' can hold. (Minimum
is 0.) */
# define USHRT_MAX 65535
/* Minimum and maximum values a `signed int' can hold.
*/
# define INT_MIN (-INT_MAX - 1)
# define INT_MAX 2147483647
/* Maximum value an `unsigned int' can hold. (Minimum is
0.) */
# define UINT_MAX 4294967295U
/* Minimum and maximum values a `signed long int' can hold.
*/
# if __WORDSIZE == 64
# define LONG_MAX 9223372036854775807L
# else
# define LONG_MAX 2147483647L
# endif
# define LONG_MIN (-LONG_MAX - 1L)
/* Maximum value an `unsigned long int' can hold. (Minimum
is 0.) */
# if __WORDSIZE == 64
# define ULONG_MAX 18446744073709551615UL
# else
# define ULONG_MAX 4294967295UL
# endif
# ifdef __USE_ISOC99
/* Minimum and maximum values a `signed long long int' can hold.
*/
# define LLONG_MAX 9223372036854775807LL
# define LLONG_MIN (-LLONG_MAX
- 1LL)
For a complete check please read the limits.h file.
The UNIX(r) or Linux1 Operating systems
offers a complete set of utilities (also the C Compiler may be understood)
like an utility, to produce software and binaries for any purpose.
Each compiled program includes a symbolic table, that may be used for debugging - See Chapter 5: The debugging of C programs.
In this section we want to list all the common utilities that "any" programer must know to get results in the development but also for a complete use of the Linux OS.
The "nm" utility
The nm lists names or symbols from object files.
For example, a classical use is the following.
[root@ftosx1 root]# nm /usr/lib/libc.a | grep time | more
After a complicated research we will get:
...
gmtime.o:
00000000 T __gmtime_r
00000018 T gmtime
00000000 W gmtime_r
localtime.o:
00000000 T __localtime_r
00000018 T localtime
00000000 W localtime_r
mktime.o:
U __localtime_r
00000000 T __mktime_internal
00000000 b localtime_offset
000006d8 T mktime
000006d8 W timelocal
strftime.o:
U mktime
00000000 T strftime
time.o:
00000000 T time
gettimeofday.o:
00000000 T __gettimeofday
00000000 W __gettimeofday_internal
00000000 W gettimeofday
settimeofday.o:
00000000 T __settimeofday
00000000 W settimeofday
adjtime.o:
...
In BASE course we wrote an utility to browse symbolic names inside libraries. Sometimes (basically before the OpenSource wave), was fundamental to know what library was necessary to link, and a complete research is fundamental.
The "strings" utility
The strings program is another very usefull tool used to know what strings are included in libs, objects or binaries. For example if we want to know what is the version for the actual kernel running in the system, the command will be:
[root@ftosx linux]# pwd
/usr/src/linux
[root@ftosx linux]# strings vmlinux | grep gcc
Linux version 2.4.7 (root@ftosx1.futuretg.com) (gcc version
3.0.1) #13 SMP Fri Aug 24 07:51:58 EDT 2001
The "objdump" utility
This function get the .h file or other info from the object file with the relative symbolic info.
objdump -b oasys -m linux -h fu.o
Of course the file "fu.o" must belong to the oasys file.
The "objcopy" utility
This utility as explain it name,copy objects inside a file to another,
without to compile, or to write programs. It uses the GNU BFD Library.
The "strip" utility
The strip utility more common removes the symbolic infomation inside objects or binaries.
Note the difference for example compiling the 5.3.c file.
[root@ftosx1 My]# gcc -g 5.3.c -o mytime
[root@ftosx1 My]# ls -al mytime
-rwxr-xr-x 1 root
root 18824 Jul 7 17:20
mytime
[root@ftosx1 My]# strip mytime
[root@ftosx1 My]# ls -al mytime
-rwxr-xr-x 1 root
root 3388 Jul 7 17:20
mytime
[root@ftosx1 My]#
Generally when a package is created the strip is made in automatic mode.
The "size" utility
The size instead prints the information about the symbolic information: text, and data information.
Note that the numbers does not changes stripping the binary.
[root@ftosx1 My]# gcc -g 5.3.c -o mytime
[root@ftosx1 My]# size mytime
text data
bss dec hex filename
1333 280
8 1621 655 mytime
[root@ftosx1 My]# strip mytime
[root@ftosx1 My]# size mytime
text data
bss dec hex filename
1333 280
8 1621 655 mytime
[root@ftosx1 My]# man size
[root@ftosx1 My]#
All these utilities are included in the binutils RPM package.
Test (Only 65 simple questions!)
Consult the answers
Check the Interactive Exam Cram Programming:
Internet Resources for this Chapter.