C only guarantees minimum and relative size of "int", "short" etc...
C only guarantees minimum and relative size of "int", "short" etc... The range that each type can represent depends on the implementation.
The integer data types range in size from at least 8 bits to at least 32 bits. The C99 standard extends this range to include integer sizes of at least 64 bits.
...
...
@@ -51,3 +51,144 @@ For example:
-`int64_t` is an signed 64-bit integer
All theses types are defined in the header file `stdint.h` instead of in the language itself.
## Undefined Behaviours
The C language standard precisely specifies the observable behavior of C language programs, except for:
- Undefined behaviours
- Unspecific behaviours
- Implementation-defined behaviours
- Locale-specific behaviours
More information about these can be found [here](https://en.cppreference.com/w/c/language/behavior).
We are going to focus on **undefined behaviours** in this section.
### What are Undefined Behaviours
- The language definition says: "We don't know what will happen, nor care of that matter".
- This often means **unpredictable behaviour**.
- Often contributes to bugs that seem random and hard to reproduce.
What we have to do is to pay attention to these possible behaviours and avoid them in the source code.
We will use **UB** and **undefined behaviours** interchangeably in the later sections.
### Frequent Undefined Behaviours
#### Signed Overflow
```c
#include< limits .h >
intfoo(inta)
{
intb=INT_MAX+a;// UB, b can be anything
returnb;
}
```
#### Division by Zero
```c
#include<stdio.h>
intfunc(){
intgv;
printf("Enter a integer number: ");
scanf("%d",&gv);
return(23/func());// UB
}
```
#### NULL Pointer Dereference
```c
intfoo(int*p)
{
intx=*p;
if(!p)
returnx;// Either UB above or this branch is never taken
else
return0;
}
intbar()
{
int*p=NULL;
return*p;// Unconditional UB
}
```
#### Value of a Pointer to Object with Ended Lifetime
```c
int*fun(intx){
inty=2;
y=x+y;
return*y;// UB
}
```
#### Use of Indeterminate Value
```c
#include<stdio.h>
intmain(){
inta;
intb=a;// UB
printf("a = %d\n",a);
printf("b = %d\n",b);
return0;
}
```
#### String Literal Modification
```c
#include<stdio.h>
intmain(){
char*p="some text here";
p[2]='O';// UB
}
```
#### Access Out Of Bounds
```c
#include<stdio.h>
intmain(){
intarr[5]={1,2,3,4,5};
intb=arr[7];// UB
printf("b = %d\n",b);
}
```
#### Pointer Used After Freed
```c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
intmain(){
charstr[9]="tutorial";
charftr[9]="aftertut";
intbufsize=strlen(str)+1;
char*buf=(char*)malloc(bufsize);
if(!buf){
returnEXIT_FAILURE;
}
free(buf);
strcpy(buf,ftr);// UB
printf("buf = %s\n",buf);
returnEXIT_SUCCESS;
}
```
This list goes on, you can find more information about undefined behaviours in this [thesis](https://solidsands.com/wp-content/uploads/Master_Thesis_Vasileios_GemistosFinal.pdf) and in the [C99 Standard](https://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf)