2. SeminarSeminar
PurposePurpose
Common MistakesCommon Mistakes
struct and Memory Paddingstruct and Memory Padding
New line characterNew line character
Binary mode in fopen()Binary mode in fopen()
strncpy()strncpy()
memset()memset()
fgets()fgets()
Non-null-terminated stringNon-null-terminated string
#include guard#include guard
Get ID of a threadGet ID of a thread
Buffer overflow, Stack overwriteBuffer overflow, Stack overwrite
3. PurposePurpose
Introduce common mistakes programmersIntroduce common mistakes programmers
often gets into while writing C codeoften gets into while writing C code
Get experiences to write better codesGet experiences to write better codes
4. Common MistakesCommon Mistakes
1. struct and Memory Padding1. struct and Memory Padding (1 of 5)(1 of 5)
//sizeof() = 12
struct myStruct
{
short s;
int i;
char c;
};
5. Common MistakesCommon Mistakes
1. struct and Memory Padding1. struct and Memory Padding (2 of 5)(2 of 5)
//sizeof() = 8
struct myStruct
{
int i;
short s;
char c;
};
//sizeof() = 8
struct myStruct
{
char c;
short s;
int i;
};
6. Common MistakesCommon Mistakes
1. struct and Memory Padding1. struct and Memory Padding (3 of 5)(3 of 5)
Memory padding is done automatically byMemory padding is done automatically by
compilercompiler
Padding increases memoryPadding increases memory but makes app tobut makes app to
run fasterrun faster
Re-order variables in struct (ascending orRe-order variables in struct (ascending or
descending) → you can reduce paddingdescending) → you can reduce padding ← your← your
experienceexperience
7. Common MistakesCommon Mistakes
1. struct and Memory Padding1. struct and Memory Padding (4 of 5)(4 of 5)
Rules of padding:Rules of padding:
A variable of a specific type will be aligned at offset = multiple of size ofA variable of a specific type will be aligned at offset = multiple of size of
that variable. If it is not so, padding will be added before itthat variable. If it is not so, padding will be added before it
Total size of struct = multiple of size of largest variable in struct. If it is notTotal size of struct = multiple of size of largest variable in struct. If it is not
so, padding will be added at the end of struct.so, padding will be added at the end of struct.
Example:Example:
Variables of type int will be aligned at offset: 0, 4, 8, 12, 16 etc …Variables of type int will be aligned at offset: 0, 4, 8, 12, 16 etc …
Variables of type char will be aligned at offset: 0, 1, 2, 3, 4, 5 etc …Variables of type char will be aligned at offset: 0, 1, 2, 3, 4, 5 etc …
Variables of type pointer will be aligned at offset: 0, 8, 16, 24, 32 etc ...Variables of type pointer will be aligned at offset: 0, 8, 16, 24, 32 etc ...
8. Common MistakesCommon Mistakes
1. struct and Memory Padding1. struct and Memory Padding (5 of 5)(5 of 5)
Sometimes, you want to avoid memorySometimes, you want to avoid memory
padding, you can usepadding, you can use #pragma pack (1)#pragma pack (1)
directivedirective
It is useful in some specific situationIt is useful in some specific situation
Save memorySave memory but your app runs slowerbut your app runs slower
#pragma pack(1) /* set alignment to 1 byte boundary */
struct MyPackedData /* sizeof() = 10 → x64 architecture */
{
char Data1;
long Data2;
char Data3;
};
#pragma pack(0) /* Back to normal */
9. Common MistakesCommon Mistakes
2. New line character2. New line character
New line character in Windows is different fromNew line character in Windows is different from
Linux:Linux:
In Windows, newline is denoted by 2 bytes: a combination of CarriageIn Windows, newline is denoted by 2 bytes: a combination of Carriage
Return (ASCII value 13) and Line Feed (ASCII value 10)Return (ASCII value 13) and Line Feed (ASCII value 10)
In Linux, newline is denoted by only 1 byte: the Line Feed character (ASCIIIn Linux, newline is denoted by only 1 byte: the Line Feed character (ASCII
value 10)value 10)
10. Common MistakesCommon Mistakes
3. Binary mode in fopen()3. Binary mode in fopen()
FILE *FILE *fopen(fopen(const char *const char *path,path, const char *const char *mode);mode);
In Windows,In Windows, text-modetext-mode andand binary-modebinary-mode areare
differentiated. e.gdifferentiated. e.g “r”“r”,, “rb”“rb”,, “w”“w”,, “wb”“wb” ……
In Linux, there is no text-mode. fopen()In Linux, there is no text-mode. fopen() alw aysalw ays
open file inopen file in binary-modebinary-mode. So,. So, “r”“r” andand “rb”“rb” areare
the same. There is no error whether you passthe same. There is no error whether you pass
“b”“b” or notor not
– fopen(“myFile.txt”, “r”);fopen(“myFile.txt”, “r”); /* prefer to use this *//* prefer to use this */
– fopen(“myFile.txt”, “rb”);fopen(“myFile.txt”, “rb”); /* In Linux, both lines are same! *//* In Linux, both lines are same! */
11. Common MistakesCommon Mistakes
4. strncpy()4. strncpy() (1 of 2)(1 of 2)
char *char *strncpy(strncpy(char *char *dest,dest, const char *const char *src,src, size_tsize_t n);n);
strncpy() always tries to copystrncpy() always tries to copy nn character fromcharacter from
srcsrc intointo destdest. If. If (m<n)(m<n) chars are copied →chars are copied → (n-m)(n-m)
number of zeros will be filled intonumber of zeros will be filled into destdest →→
always copiesalways copies nn characters intocharacters into destdest
So, the following codes mightSo, the following codes might C R AS H!!!C R AS H!!!
charchar str[str[55];];
strncpy(str,strncpy(str, “abc”“abc”,, 1010);); /* Will copy “abc” and 7 zeros into str *//* Will copy “abc” and 7 zeros into str */
12. Common MistakesCommon Mistakes
4. strncpy()4. strncpy() (2 of 2)(2 of 2)
The following codes is redundantThe following codes is redundant
– charchar str[str[1010];];
– memset (str,memset (str, 00,, 1010);); /* ← No need, strncpy() will do the thing *//* ← No need, strncpy() will do the thing */
– strncpy(str,strncpy(str, “abc”“abc”,, 1010);); /* Will copy “abc” and 7 zeros into str *//* Will copy “abc” and 7 zeros into str */
13. Common MistakesCommon Mistakes
5. memset()5. memset()
OnlyOnly use memset() to initialize variables touse memset() to initialize variables to
ZEROZERO
N E V E RN E V E R use memset() to initialize variables touse memset() to initialize variables to
any values rather than zeroany values rather than zero
Since, memset() fills memory with units inSince, memset() fills memory with units in bytebyte
14. Common MistakesCommon Mistakes
6. fgets()6. fgets()
char *char *fgets(fgets(char *char *s,s, intint size,size, FILE *FILE *stream);stream);
fgets() only reads at mostfgets() only reads at most (size -1)(size -1) chars fromchars from
streamstream intointo ss and then addsand then adds '0''0' at the end ofat the end of ss
It reads only (size -1) charactersIt reads only (size -1) characters
15. Common MistakesCommon Mistakes
6. Non-null-terminated string6. Non-null-terminated string
When working withWhen working with non-null-terminatednon-null-terminated string,string,
do not usedo not use “%s”“%s”. Instead, use. Instead, use “%.*s”“%.*s”
– voidvoid display(display(charchar **msg)msg)
– {{
• printf(printf(“The msg: %.256s”“The msg: %.256s”, msg);, msg);
• printf(printf(“The msg: %.*s”“The msg: %.*s”,, 256256, msg);, msg); /* does the same thing *//* does the same thing */
– }}
16. Common MistakesCommon Mistakes
7. #include guard7. #include guard (1 of 3)(1 of 3)
Problem:Problem:
When compiling main.c: mylib.h is included twice → declarations areWhen compiling main.c: mylib.h is included twice → declarations are
overwrittenoverwritten
mylib.h is openedmylib.h is opened tw ic etw ic e → compiler time→ compiler time definitelydefinitely increasesincreases
main.c file1.h file2.h mylib.h
#include “file1.h”
#include “file2.h”
#include “mylib.h”
/* something belongs to file1 */
#include “mylib.h”
/* something belongs to file2 */
extern int i;
17. Common MistakesCommon Mistakes
7. #include guard7. #include guard (2 of 3)(2 of 3)
S olution:S olution: #inc lude g uard#inc lude g uard
When compiling main.c: mylib.h is included once!When compiling main.c: mylib.h is included once!
Depends on compiler (supports include guard optimisation or not): mylib.hDepends on compiler (supports include guard optimisation or not): mylib.h
is openedis opened onc eonc e oror tw ic etw ic e → compiler time may reduce or not→ compiler time may reduce or not
Most of compilers support “include guard optimisation feature”: the includeMost of compilers support “include guard optimisation feature”: the include
guard is cached at the first call, later the file (mylib.h) will not be opened →guard is cached at the first call, later the file (mylib.h) will not be opened →
compiler time is fastercompiler time is faster
main.c file1.h file2.h mylib.h
#include “file1.h”
#include “file2.h”
#include “mylib.h”
/* something belongs to file1 */
#include “mylib.h”
/* something belongs to file2 */
#ifndef MYLIB_H
#define MYLIB_H
extern int i;
#endif
18. Common MistakesCommon Mistakes
7. #include guard7. #include guard (3 of 3)(3 of 3)
S olution:S olution: #inc lude g uard (optimized)#inc lude g uard (optimized)
When compiling main.c: mylib.h is included once!When compiling main.c: mylib.h is included once!
mylib.h is openedmylib.h is opened onc eonc e → faster→ faster
Must insert #ifndef everywhere when calling #include → only use with veryMust insert #ifndef everywhere when calling #include → only use with very
large project to reduce the compiler timelarge project to reduce the compiler time
Us eles sUs eles s if the compiler supports “include guard optimisation feature”if the compiler supports “include guard optimisation feature”
main.c file1.h file2.h mylib.h
#include “file1.h”
#include “file2.h”
#ifndef MYLIB_H
#include “mylib.h”
#endif
/* something belongs to file1 */
#ifndef MYLIB_H
#include “mylib.h”
#endif
/* something belongs to file2 */
#ifndef MYLIB_H
#define MYLIB_H
extern int i;
#endif
19. Common MistakesCommon Mistakes
8. Get ID of a thread8. Get ID of a thread
Get ID of a process is easy (Get ID of a process is easy (pid_tpid_t getpid(getpid(voidvoid););). How). How
about thread?about thread?
#include#include <sys/syscall.h><sys/syscall.h>
#define#define gettid()gettid() syscall(__NR_gettid)syscall(__NR_gettid)
printf (printf ( "Thread ID: %dn""Thread ID: %dn", gettid() );, gettid() );
20. Common MistakesCommon Mistakes
9. Buffer Overflow, Stack Overwrite9. Buffer Overflow, Stack Overwrite
Don't write the following codes, it will overwriteDon't write the following codes, it will overwrite
some important data in your application:some important data in your application:
intint GlobalBuffer[GlobalBuffer[1010][][2020];];
voidvoid InitializeBuffer()InitializeBuffer()
{{
intint i, j;i, j;
forfor (i =(i = 00; I <; I < 100100; i++); i++) /* You go out off the boundary *//* You go out off the boundary */
forfor (j =(j = 00; j <; j < 2121; j++); j++) /* Again, go out off the boundary *//* Again, go out off the boundary */
GlobalBuffer[i][j] =GlobalBuffer[i][j] = 00;;
}}
Youthinkyouwillnever besilly likethis? Yep, u'r rite, but sometimesyoumake mistake like this!Youthinkyouwillnever besilly likethis? Yep, u'r rite, but sometimesyoumake mistake like this!
21. Thanks for watchingThanks for watchingIf you see it useful → clap your hands :-)If you see it useful → clap your hands :-)