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
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...5164 
 Trees...935 
 Максвелл 3...861 
 Go Web ...814 
 William Gropp...796 
 Ethreal 3...779 
 Ethreal 4...766 
 Gary V.Vaughan-> Libtool...765 
 Rodriguez 6...756 
 Steve Pate 1...749 
 Ext4 FS...748 
 Clickhouse...748 
 Ethreal 1...736 
 Secure Programming for Li...721 
 C++ Patterns 3...711 
 Ulrich Drepper...693 
 Assembler...687 
 DevFS...655 
 Стивенс 9...644 
 MySQL & PosgreSQL...622 
 
  01.01.2024 : 3621733 посещений 

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. Оставьте свой комментарий !

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

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