Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
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. Оставьте свой комментарий !

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

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