1. Homepage of Dr. Zoltán Porkoláb
    1. Home
    2. Archive
  2. Teaching
    1. Timetable
    2. Multiparadigm programming (MSc)
    3. C programming (BSc for physicists)
    4. Project tools (BSc)
    5. Bolyai College
    6. C++ (for foreign studenst)
    7. Software technology lab
    8. BSc and MSc thesis
  3. Research
    1. Templight
    2. CodeChecker
    3. CodeCompass
    4. Projects
    5. Publications (up to 2011)
    6. PhD students
  4. Affiliations
    1. Dept. of Programming Languages and Compilers
    2. Ericsson Hungary Ltd

The C programming language – Lecture 3.

Preprocessor directives

Preprocessing is the first steps of the C translation process.

  1. Trigraph replacement (trigraph characters are replaced).
  2. Line splicing (lines ending with escaped newlines are spliced).
  3. Tokenization (and replacing comments with whitespace).
  4. Macro expansion and directive handling.

Digraphs and trigraphs

The required character set of the programming language and the usual input devices (e.g. keyboard) may differ.

Not only in C, Pascal also supports digraphs:

(.    -->   [
.)    -->   ]
(*    -->   {
*)    -->   }

C language trigraphs:

??=   -->   #
??/   -->   \
??'   -->   ^
??(   -->   [
??)   -->   ]
??!   -->   |
??<   -->   {
??>   -->   }
??-   -->   ~
1
2
3
4
5
6
7
8
9
printf("How are you??-I am fine")  -->  printf("How are you~I am fine")
printf("How are you???-I am fine")  -->  printf("How are you?~I am fine")

// Will the next line be executed??????/
a++;                  -->  // Will the next line be executed???? a++;

/??/
 * A comment *??/
/                      --> /* A comment */

Digraphs (from C99) handled in tokenization (step 4.)

<:   -->   [
:>   -->   ]
<%   -->   {
%>   -->   }
%:   -->   #

Include directive handling

#include <filename>

Search filename in the standard compiler include path

#include "filename"

Search filename in the current source directory

$ g++ -I/usr/local/include/add/path1 -I/usr/local/include/add/path2 ...

Extend the include path from command line

The preprocessor replaces the line with the text of the filename.

1
2
3
4
5
6
#include <stdio.h>
int main(void)
{
    printf("Hello, world!\n");
    return 0;
}

Macro definition

Object-like macro:

#define <identifier>  <token-list> 

Examples:

1
2
3
4
5
6
7
#define BUFSIZE    1024
#define PI         3.14159
#define USAGE_MSG  "Usage: command -flags args..."
#define LONG_MACRO struct MyType \
                   {             \
                     int data;   \
                   };     

Usage:

1
2
char buffer[BUFSIZE];
fgets(buffer, BUFSIZE, stdin);

Function-like macro

#define <identifier>(<param-list>)  <token-list>

Examples:

1
2
#define FAHR2CELS(x)  ((5./9.)*(x-32))
#define MAX(a,b)  ((a) > (b) ? (a) : (b))

Usage:

1
2
3
c = FAHR2CELS(f);
x = MAX(x,-x);
x = MAX(++y,z);

Undefine macros

1
#undef BUFSIZE

Conditional compilation

1
2
3
#if DEBUG_LEVEL > 2
  fprint("program was here %s %d\n", __FILE__, __LINE__);
#endif
1
2
3
4
5
#ifdef __unix__ /* __unix__ is usually defined by compilers for Unix */
#  include <unistd.h>
#elif defined _WIN32 /* _Win32 is usually defined for 32/64 bit Windows */
#  include <windows.h>
#endif
1
2
3
4
5
#if !(defined( __unix__ ) || defined (_WIN32) )
  // ...
#else
  // ...
#endif

Error

1
2
3
#if RUBY_VERSION == 190
# error 1.9.0 not supported
#endif

Line

#line 567

Header guards

To avoid multiple inclusion:

1
2
3
4
5
6
7
#ifndef MY_HEADER_H
#define MY_HEADER_H
/* 
 * content of header file 
 * 
 */
#endif /* MY_HEADER_H */

Alternative solution:

1
2
3
4
5
#pragma ones
/* 
 * content of header file 
 * 
 */

Standard defined macros

1
2
3
4
5
6
7
8
__FILE__
__LINE__
__DATE__
__TIME__

__STDC__
__STDC_VERSION__
__cplusplus
1
2
3
4
5
6
7
#ifdef __cplusplus
extern C {
#endif
// ...
#ifdef __cplusplus
}
#endif

Pragma

1
#pragma warning(disable:4786)

Token stringification

1
2
3
4
5
#define str(s) #s
#define BUFSIZE 1024
// ...
str(\n)       -->   "\n"
str(BUFSIZE)  -->   1024

Token concatenation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct my_int_20_array
{
  int v[20];
};
struct my_int_30_array
{
  int v[30];
};
struct my_double_40_array
{
  double v[40];
};

#define DECLARE_ARRAY(NAME, TYPE, SIZE) \
typedef struct TYPE##_##SIZE##_array    \
{                                       \
  TYPE v[SIZE];                         \
                                        \
} NAME##_t;

DECLARE_ARRAY(yours,float,10);
yours_t x, y;