It exists instructions with 0, 1, 2, 3... operands. As C is a portable language, a C instruction does not necessarily corresponds to a single CPU instruction. For the remaining, "instruction" will be use to designate a C instruction ie a list of words that terminates with a ;
C instructions are grouped into blocks, delimited by { }
To begin, let us consider that some of these blocks can be named. A named block is a function. The first block to be executed is the block named main : main(){inst1; inst2; ...;}
To designate the operations, C uses key words: (+,-,/,+=,=,==,...). To designates operands (that can be either values or memory adresses) C uses the notions of variable and type. Declaring a variable means reserving a name to designate a specific memory address, while specifying in the same time the type of the data that will be store there, that is to say, its size in byte (example integer = 32 or 64 bits on most of the CPUs) and the operation to use for some of them that are written the same way (example: the integer division is different from the division on real numbers, but both are written in C with /).
For the program, the memory is an infinite array of bytes. This array is not use randomly. The beginning contains reserved data for the process (pid, ppid, file descriptors, environment...). Then came the program instructions. After came an area called the stack. Finally, the last address (the biggest that can be encoded with an integer value) is the beginning of the heap, that grows from the right to the left.
On the following, we will just represent the stack part, and vertically (the bottom being the first address of the stack). Let get back to the add example and look at what happens on the stack:
The first step consist in memory reservation, giving names to reserved area (in order to be able to use them late): int a; int b; int res; The type must be written in order to know the size of the area to reserve. This is called variable declarions. Then, the reserved area can be fill: a=2; b=3; This is called variable initializations.
The "a+b;" instruction is correct. However there is no side effect on the stack. In order to be usefull, the result of this instruction must be affected to a variable: res=a+b;
C is a strongly typed language. Every expressions have a type. Allowed type are structures, alias (with typedef) and primitive types : int, char, float,... A type is characterized by its size in bytes. The special function sizeof() permits to obtain the size of a type. The instruction "sizeof(char);" for example is equal to 1. The C specification only says:
data type | means | syze (octet/byte) | Range of value | ||||||
char | Character | 1 | -128 à 127 | ||||||
unsigned char | unsigned character | 1 | 0 à 255 | ||||||
short int | short integer | 2 | -32 768 à 32 767 | ||||||
unsigned short int | unsigned short integer | 2 | 0 à 65 535 | ||||||
int | integer |
|
| ||||||
unsigned int | unsigned integer |
|
| ||||||
long int | long integer |
|
| ||||||
unsigned long int | unsigned long integer |
|
| ||||||
float | Floating point number (real) | 4 | 3.4*10^-38 à 3.4*10^38 | ||||||
double | Floating point number double precision | 8 | 1.7*10^-308 à 1.7*10^308 | ||||||
long double | long double | 10 | 3.4*10^-4932 à 3.4*10^4932 |
Formally, an expression is a part of code which begins after a ; and terminates at the next ; Every expressions have a value and can have a side effect (ie modify the stack or more generally the memory). As every expression have value, it is possible to compare them one by one this operators ==, <, > <=, >=; or to assign their value to a variable with =. The combination then is a bigger expression, only the final ; is kept
example