Common mistakes in C programming

6,089 views
5,903 views

Published on

Describe some basic mistakes when programming with C

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,089
On SlideShare
0
From Embeds
0
Number of Embeds
12
Actions
Shares
0
Downloads
136
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Common mistakes in C programming

  1. 1. Article: CommonArticle: Common Mistakes In CMistakes In C ProgrammingProgramming By Khanh Ngo-DuyBy Khanh Ngo-Duy Khanhnd@elarion.comKhanhnd@elarion.com
  2. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 21. Thanks for watchingThanks for watchingIf you see it useful → clap your hands :-)If you see it useful → clap your hands :-)

×