Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
=> Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
NEWS
Последние статьи :
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
  SQL 30.07   
  JFS 10.06   
  B-trees 01.06   
 
TOP 20
 Go Web ...611 
 2.0-> Linux IP Networking...363 
 Secure Programming for Li...298 
 2.6-> Kernel 2.6.17...230 
 William Gropp...228 
 Kamran Husain...225 
 Robbins 4...218 
 Advanced Bash Scripting G...215 
 Ethreal 1...209 
 Rodriguez 9...204 
 Rodriguez 6...197 
 UML 3...195 
 Steve Pate 3...193 
 Стивенс 8...193 
 Advanced Bash Scripting G...192 
 Daniel Bovet 2...191 
 Steve Pate 1...189 
 Kamran Husain...187 
 Rodriguez 8...184 
 Kernel Notes...179 
 
  01.03.2019 : 2682145 посещений 

iakovlev.org

Как избежать ошибок в "C"

Надо сказать , что в последнее время С не стоит на месте , и авторы новейших юниксовых компиляторов предприняли кое-какие шаги для того , чтобы предупреждать простых смертных о возможных потенциальных ошибках в коде .

  1. Незаконченные комментарии
  2.  a=b; /* this is a bug
    c=d; /* c=d will never happen */
  3. Неправильная инициализация
  4.  if(a=b) c; /* a всегда равно b, но c верно и при if b!=0 */
    Здесь легко попасть впросак , написав вместо 2-х знаков равенства один , и С ничем не сможет вам тут помочь : (a=b) это совсем не булевское выражение!

    Или рассмотрим такую конструкцию:

     if( 0 < a < 5) c; /* this "boolean" is always true! */
    Тут всегда true , потому что (0<a) - это либо 0 либо 1 , что естественно меньше 5.

    Или:

    if( a =! b) c; /* будет скомпилировано как (a = !b), т.е. присваивание, и совсем не (a != b) или (a == !b) */

  5. Неправильный macros
  6.  #define assign(a,b) a=(char)b
    assign(x,y>>8)
    превращается в
    x=(char)y>>8 /* совсем не то чего мы хотим */
  7. Несоответствие хидеров

  8. Пусть foo.h включает:
     struct foo { BOOL a};

    файл F1.c включает
    #define BOOL char
    #include "foo.h"

    файл F2.c включает
    #define BOOL int
    #include "foo.h"
    В файлах F1 и F2 налицо противоречие при компиляции .
  9. Неопределенное возвращаемое значение

  10. Ну и теперь предположим мы написали
     int foo (a)
    { if (a) return(1); } /* баг - при некоторых условиях функция может вообще ничего не вернуть */
    Компилятор не скажет вам , где ошибка . И можете получить например зацикливание .

    Или более того - представьте что эта функция вернет указатель !

  11. Непредсказуемое поведение структуры

  12. Рассмотрим структуру:
     struct eeh_type
    {
    uint16 size: 10; /* 10 bits */
    uint16 code: 6; /* 6 bits */
    };
    В зависимости от компилятора-платформы , это может быть трактовано как
     <10-bits><6-bits>
    или
     <6-bits><10-bits>

  13. Неопределенный порядок аргументов (
  14.  foo(pointer->member, pointer = &buffer[0]);
    Компилятор gcc скушает и не поморщится , но не acc. gcc берет аргументы слева направо , в то время как acc - справа налево .

    Кстати , K&R and ANSI/ISO C не определяет этот порядок . Он может быть слева-направо , справа-налево или вообще каким угодно .

  15. Неправильный блок кода
  16.  if( ... )
    foo();
    else
    bar();
    и сравните вот с этим
     if( ... )
    foo(); /* the importance of this semicolon can't be overstated */
    else
    printf( "Calling bar()" ); /* oops! the else stops here */
    bar(); /* oops! bar is always executed */
    За такое конечно надо руки отрывать ...
  17. Permissive compilation (suggested by James M. Stern <jstern@world.nad.northrop.com>)

  18. Однажды я модифицировал код через макрос следующим образом :
     CALLIT(functionName,(arg1,arg2,arg3));
    Затем я удалаил вызов CALLIT:
     functionName,(arg1,arg2,arg3);
    Функция перестала вызываться.
    Или так:
     switch (a) {
    int var = 1; /* Этой инициализации как правило не суждено сбыться. */
    /* The compiler doesn't complain, but it sure screws things up! */
    case A: ...
    case B: ...
    }
    Или попробуйте так:
    #define DEVICE_COUNT 4
    uint8 *szDevNames[DEVICE_COUNT] = {
    "SelectSet 5000",
    "SelectSet 7000"}; /* table has two entries of junk */
  19. Незащищенные возвращаемые данные
  20. char *f() {
    char result[80];
    sprintf(result,"anything will do");
    return(result); /* Oops! result - то в стеке. */
    }

    int g()
    {
    char *p;
    p = f();
    printf("f() returns: %s\n",p);
    }
    Все будет хорошо до тех пор , пока кто-нибудь не забьет стек ...

  21. Неопределенные побочные эффекты
  22. Например, I/++I может быть как 0 так и 1. Или:

    #include<stdio .h>

    int foo(int n) {printf("Foo got %d\n", n); return(0);}

    int bar(int n) {printf("Bar got %d\n", n); return(0);}

    int main(int argc, char *argv[])
    {
    int m = 0;
    int (*(fun_array[3]))();

    int i = 1;
    int ii = i/++i;

    printf("\ni/++i = %d, ",ii);

    fun_array[1] = foo; fun_array[2] = bar;

    (fun_array[++m])(++m);
    }

    Prints either i/++i = 1 or i/++i=0;
    Может быть отпечатано "Foo got 2", а может быть "Bar got 2"
  23. Непроинициализированные локальные переменные
  24. Бага широко известная . Рассмотрим пример:

    void foo(a)
    { int b;
    if(b) {/* bug! b is not initialized! */ }
    }
    Или:
    void foo(int a)
    { BYTE *B;
    if(a) B=Malloc(a);
    if(B) { /* BUG! B may or may not be initialized */ *b=a; }
    }
  25. Cluttered compile time environment
  26. Рассмотрим пример :

    #include <stdio.h>
    #define BUFFSIZE 2048
    long foo[BUFSIZ]; //note spelling of BUFSIZ != BUFFSIZE

    Компиляция пройдет без ошибок , но ошибка в том , что BUFSIZ уже определена в stdio.h. Иногда подобные ошибки трудно отискать.

  27. Underconstrained fundamental types

  28. Не секрет , что в зависимости от платформы или версии компилятора размер фундаментального типа int может быть 16 , а может и 32 бита..
  29. Utterly unsafe arrays
  30. Пример :

    int thisIsNuts[4]; int i;
    for ( i = 0; i < 10; ++i )
    {
    thisIsNuts[ i ] = 0; /* Недурно , не правда ли ? Я использую элементы с порядковыми номерами 1-10 при том , что массив-то всего из 4 элементов */
    }


  31. Octal numbers
  32. В C, числа начинающиеся с нуля , ассоциируются с системой счисления 8.

    int numbers[] = { 001, // красиво , но не рационально
    010, // 8 , а не 10
    014 }; // 12, а не 14

  33. Signed Characters/Unsigned bytes.
    В C введен unsigned для целых типов. С другой стороны , тот факт , что тип char или byte может быть знаковым , тоже является своего рода проблемой .

    char s = 127;
    unsigned char u = 127;
    s++; /* результат - отрицательное число! */
    if (s<u) { /* true!*/ }
    if(s>127) { /* this can never be true */ }
    if(u<0) { /* this can never be true*/ }


  34. Оставьте свой комментарий !

    Ваше имя:
    Комментарий:
    Оба поля являются обязательными

     Автор  Комментарий к данной статье