Что принадлежит образовательному инструменту, чтобы продемонстрировать необоснованные предположения, которые люди делают в C /C ++?

Я хотел бы подготовить небольшой обучающий инструмент для SO, который должен помочь начинающим (и средним) программистам распознавать и оспаривать их необоснованные предположения в C, C ++ и их платформах.

Примеры:

  • "целые числа"
  • "у всех есть ASCII"
  • "Я могу сохранить указатель на функцию в пустоте *"

Я подумал, что небольшая тестовая программа может быть запущена на различных платформах, которая основывается на «правдоподобных» предположениях, которые, исходя из нашего опыта в SO, обычно делаются многими неопытными /опытными мейнстримовыми разработчиками, и записывают, как они ломаются на различных машины.

Цель этого состоит не в том, чтобы доказать, что что-то «безопасно» делать (что было бы невозможно сделать, тесты доказывают только что-либо, если они сломались), а в том, чтобы продемонстрировать даже самому непонимающему человеку как самое незаметное выражение ломается на другом компьютере, если оно имеет неопределенное или определяемое реализацией поведение. .

Для достижения этой цели я хотел бы попросить вас:

  • Как можно улучшить эту идею?
  • Какие тесты будут хорошими и как они должны выглядеть?
  • Будете ли вы запускать тесты на платформах, которые вы можете получить и опубликовать результаты, чтобы мы получили базу данных платформ, как они отличаются и почему это различие допускается?

Вот текущая версия тестовой игрушки:

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <stddef.h>
int count=0;
int total=0;
void expect(const char *info, const char *expr)
{
    printf("..%s\n   but '%s' is false.\n",info,expr);
    fflush(stdout);
    count++;
}
#define EXPECT(INFO,EXPR) if (total++,!(EXPR)) expect(INFO,#EXPR)

/* stack check..How can I do this better? */
ptrdiff_t check_grow(int k, int *p)
{
    if (p==0) p=&k;
    if (k==0) return &k-p;
    else return check_grow(k-1,p);
}
#define BITS_PER_INT (sizeof(int)*CHAR_BIT)

int bits_per_int=BITS_PER_INT;
int int_max=INT_MAX;
int int_min=INT_MIN;

/* for 21 - left to right */
int ltr_result=0;
unsigned ltr_fun(int k)
{
    ltr_result=ltr_result*10+k;
    return 1;
}

int main()
{
    printf("We like to think that:\n");
    /* characters */
    EXPECT("00 we have ASCII",('A'==65));
    EXPECT("01 A-Z is in a block",('Z'-'A')+1==26);
    EXPECT("02 big letters come before small letters",('A'<'a'));
    EXPECT("03 a char is 8 bits",CHAR_BIT==8);
    EXPECT("04 a char is signed",CHAR_MIN==SCHAR_MIN);

    /* integers */
    EXPECT("05 int has the size of pointers",sizeof(int)==sizeof(void*));
    /* not true for Windows-64 */
    EXPECT("05a long has at least the size of pointers",sizeof(long)>=sizeof(void*));

    EXPECT("06 integers are 2-complement and wrap around",(int_max+1)==(int_min));
    EXPECT("07 integers are 2-complement and *always* wrap around",(INT_MAX+1)==(INT_MIN));
    EXPECT("08 overshifting is okay",(1<<bits_per_int)==0);
    EXPECT("09 overshifting is *always* okay",(1<<BITS_PER_INT)==0);
    {
        int t;
        EXPECT("09a minus shifts backwards",(t=-1,(15<<t)==7));
    }
    /* pointers */
    /* Suggested by jalf */
    EXPECT("10 void* can store function pointers",sizeof(void*)>=sizeof(void(*)()));
    /* execution */
    EXPECT("11 Detecting how the stack grows is easy",check_grow(5,0)!=0);
    EXPECT("12 the stack grows downwards",check_grow(5,0)<0);

    {
        int t;
        /* suggested by jk */
        EXPECT("13 The smallest bits always come first",(t=0x1234,0x34==*(char*)&t));
    }
    {
        /* Suggested by S.Lott */
        int a[2]={0,0};
        int i=0;
        EXPECT("14 i++ is strictly left to right",(i=0,a[i++]=i,a[0]==1));
    }
    {
        struct {
            char c;
            int i;
        } char_int;
        EXPECT("15 structs are packed",sizeof(char_int)==(sizeof(char)+sizeof(int)));
    }
    {
        EXPECT("16 malloc()=NULL means out of memory",(malloc(0)!=NULL));
    }

    /* suggested by David Thornley */
    EXPECT("17 size_t is unsigned int",sizeof(size_t)==sizeof(unsigned int));
    /* this is true for C99, but not for C90. */
    EXPECT("18 a%b has the same sign as a",((-10%3)==-1) && ((10%-3)==1));

    /* suggested by nos */
    EXPECT("19-1 char<short",sizeof(char)<sizeof(short));
    EXPECT("19-2 short<int",sizeof(short)<sizeof(int));
    EXPECT("19-3 int<long",sizeof(int)<sizeof(long));
    EXPECT("20 ptrdiff_t and size_t have the same size",(sizeof(ptrdiff_t)==sizeof(size_t)));
#if 0
    {
        /* suggested by R. */
        /* this crashed on TC 3.0++, compact. */
        char buf[10];
        EXPECT("21 You can use snprintf to append a string",
               (snprintf(buf,10,"OK"),snprintf(buf,10,"%s!!",buf),strcmp(buf,"OK!!")==0));
    }
#endif

    EXPECT("21 Evaluation is left to right",
           (ltr_fun(1)*ltr_fun(2)*ltr_fun(3)*ltr_fun(4),ltr_result==1234));

    {
    #ifdef __STDC_IEC_559__
    int STDC_IEC_559_is_defined=1;
    #else 
    /* This either means, there is no FP support
     *or* the compiler is not C99 enough to define  __STDC_IEC_559__
     *or* the FP support is not IEEE compliant. */
    int STDC_IEC_559_is_defined=0;
    #endif
    EXPECT("22 floating point is always IEEE",STDC_IEC_559_is_defined);
    }

    printf("From what I can say with my puny test cases, you are %d%% mainstream\n",100-(100*count)/total);
    return 0;
}

О, и я создал эту вики-сообщество с самого начала, потому что я решил, что люди захотят отредактировать мой болтун, когда прочтут это.

ОБНОВЛЕНИЕ . Спасибо за ваш вклад. Я добавил несколько случаев из ваших ответов и посмотрю, смогу ли я настроить github для этого, как предложил Грег.

UPDATE : Для этого я создал репозиторий github, файл "gotcha.c":

Пожалуйста, ответьте здесь с исправлениями или новыми идеями, чтобы их можно было обсудить или уточнить здесь. Я объединю их в gotcha.c тогда.

117 голосов | спросил 7 revs, 3 users 99%
Nordic Mainframe
1 Jam1000000amThu, 01 Jan 1970 03:00:00 +030070 1970, 03:00:00

23 ответа


0

Порядок вычисления подвыражений, в том числе

  • аргументы вызова функции и
  • операнды операторов (например, +, -, =, * , /), за исключением:
    • двоичные логические операторы (&& и ||),
    • троичный условный оператор (?:) и
    • оператор запятой (,)

Не указано

Например

  int Hello()
  {
       return printf("Hello"); /* printf() returns the number of 
                                  characters successfully printed by it
                               */
  }

  int World()
  {
       return printf("World !");
  }

  int main()
  {

      int a = Hello() + World(); //might print Hello World! or World! Hello
      /**             ^
                      | 
                Functions can be called in either order
      **/
      return 0;
  } 
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

sdcc 29,7 /ucSim /Z80

We like to think that:
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..19-2 short<int
   but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
   but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
From what I can say with my puny test cases, you are Stop at 0x0013f3: (106) Invalid instruction 0x00dd

printf вылетает. "О_О"


gcc [email protected]_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 79% mainstream

gcc [email protected]_64-suse-linux (-O2)

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 82% mainstream

clang [email protected]_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 72% mainstream

open64 [email protected]_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 75% mainstream

intel [email protected]_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 75% mainstream

Turbo C ++ /DOS /Small Memory

We like to think that:
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 81% mainstream

Turbo C ++ /DOS /средняя память

We like to think that:
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..10 void* can store function pointers
but 'sizeof(void*)>=sizeof(void(*)())' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 78% mainstream

Turbo C ++ /DOS /Compact Memory

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..20 ptrdiff_t and size_t have the same size
but '(sizeof(ptrdiff_t)==sizeof(size_t))' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 75% mainstream

cl65 @ Commodore PET (вице-эмулятор)

альтернативный текст http://i34.tinypic.com/2hh0zmc.png


Я буду обновлять их позже:


Borland C ++ Builder 6.0 в Windows XP

..04 a char is signed
   but 'CHAR_MIN==SCHAR_MIN' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..16 malloc()=NULL means out of memory
   but '(malloc(0)!=NULL)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 71% mainstream

Visual Studio Express 2010 C ++ CLR, Windows 7, 64-разрядная версия

(должен быть скомпилирован как C ++, потому что компилятор CLR не поддерживает чистый C)

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream

MINGW64 (предварительная версия gcc-4.5.2)

- http://mingw-w64.sourceforge.net/

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..05a long has at least the size of pointers
   but 'sizeof(long)>=sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 67% mainstream

64-битная Windows использует модель LLP64: и int, и long определены как 32-разрядные, что означает, что ни один не является достаточно длинным для указателя.


avr-gcc 4.3.2 /ATmega168 (Arduino Diecimila)

Неудачные предположения:

..14 i++ is structly left to right
..16 malloc()=NULL means out of memory
..19-2 short<int
..21 Evaluation is left to right
..22 floating point is always IEEE

Atmega168 имеет 16-битный ПК, но код и данные находятся в разных адресных пространствах. У более крупного Atmegas 22-битный ПК!


gcc 4.2.1 в MacOSX 10.6, скомпилированный с -arch ppc

We like to think that:
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits come always first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Давным-давно я преподавал C из учебника, в котором было

printf("sizeof(int)=%d\n", sizeof(int));

как пример вопроса. Для ученика это не удалось, потому что sizeof возвращает значения типа size_t, а не int, int в этой реализации было 16 бит, а size_t было 32, и это был big-endian. (Платформа была Lightspeed C на Macintosh на базе 680x0. Я сказал, что это было давно.)

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Вам необходимо включить ++ и -- предположения, которые делают люди.

a[i++]= i;

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

Любое утверждение, которое имеет ++ (или --) и переменная, которая встречается более одного раза, является проблемой.

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Очень интересно!

Другие вещи, которые я могу придумать, могут быть полезны для проверки:

  • существуют ли указатели функций и указатели данных в одном и том же адресном пространстве? (Разрывы в машинах гарвардской архитектуры, таких как DOS small mode. Однако не знаю, как бы вы это проверили.)

  • если вы берете указатель данных NULL и приводите его к соответствующему целочисленному типу, имеет ли он числовое значение 0? (Разрывы на некоторых действительно древних машинах - см. http://c-faq.com/null/machexamp.html .) То же самое с указателем на функцию. Также они могут иметь разные значения.

  • вызывает ли приращение указателя за концом соответствующего объекта хранилища, а затем обратно, разумные результаты? (Я не знаю ни одной машины, на которой это действительно работает, но я полагаю, что спецификация C не позволяет вам даже думать об указателях, которые не указывают ни на (a) содержимое массив или (b) элемент сразу после массива или (c) NULL. См. http: //c -faq.com/aryptr/non0based.html .)

  • сравнивает два указателя с разными объектами хранения с помощью <и> производить последовательные результаты? (Я могу представить себе это нарушение на экзотических машинах на основе сегментов; спецификация запрещает такие сравнения, поэтому компилятор будет иметь право сравнивать только смещенную часть указателя, а не часть сегмента.)

Хм. Я постараюсь придумать еще.

Изменить. Добавил несколько поясняющих ссылок на превосходный FAQ по C.

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Я думаю, вы должны попытаться провести различие между двумя очень разными классами «неправильных» предположений. Хорошая половина (сдвиг вправо и расширение знака, ASCII-совместимое кодирование, память линейна, данные и функциональные указатели совместимы и т. Д.) Являются довольно разумными предположениями для большинства C-кодеров, которые могут быть созданы, и даже быть включенным как часть стандарта, если C разрабатывался сегодня, и если у нас не было наследства устаревшего барахла IBM. Другая половина (вещи, связанные с алиасами памяти, поведением библиотечных функций, когда память ввода и вывода перекрывается, 32-битные предположения, подобные указателям, помещаются в int или что вы можете использовать malloc без прототипа, это соглашение о вызовах одинаково для функций с переменными и не переменными числами, ...) либо конфликт с оптимизацией, которую хотят выполнить современные компиляторы, либо с переходом на 64-битные машины или другие новые технологии.

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Ну, классические предположения о переносимости, которые еще не подразумевались, являются

  • предположения о размере целочисленных типов
  • порядок байт
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0
  • Ошибки дискретизации из-за представления с плавающей запятой. Например, если вы используете стандартную формулу для решения квадратных уравнений, или конечные разности для приближенных производных, или стандартную формулу для вычисления отклонений, точность будет потеряна из-за вычисления различий между подобными числами. Алгоритм Гаусса для решения линейных систем плох, потому что накапливаются ошибки округления, поэтому используются разложение QR или LU, разложение Холецкого, SVD и т. Д. Добавление чисел с плавающей запятой не ассоциативно. Существуют денормальные, бесконечные и NaN-значения. a + b - a ≠ b .

  • Строки: разница между символами, кодовыми точками и единицами кода. Как Unicode реализован в различных операционных системах; Unicode-кодировки Открытие файла с произвольным именем файла Unicode невозможно с помощью C ++ в переносимом виде.

  • Условия гонки, даже без многопоточности: если вы проверите, существует ли файл, результат может стать недействительным в любое время.

  • ERROR_SUCCESS = 0

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Вот забавный вопрос: что не так с этой функцией?

float sum(unsigned int n, ...)
{
    float v = 0;
    va_list ap;
    va_start(ap, n);
    while (n--)
        v += va_arg(ap, float);
    va_end(ap);
    return v;
}

[Ответ (rot13): Inevnqvp nethzragf borl gur byq X & E cebzbgvba ehyrf, juvpu zrnaf lbh pnaabg hfr 'sybng' (be 'pune' be 'fubeg') va in_net! Нак гур пбзцвире vf erdhverq abg gb gerng guvf nf n pbzcvyr-gvzr reebe. (TPP qbrf rzvg n jneavat, gubhtu.)]

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0
EXPECT("## pow() gives exact results for integer arguments", pow(2, 4) == 16);

Еще один - текстовый режим в fopen. Большинство программистов предполагают, что текст и двоичный код одинаковы (Unix) или что текстовый режим добавляет символы \r (Windows). Но C был перенесен в системы, которые используют записи фиксированной ширины, в которых fputc('\n', file) в текстовом файле означает добавлять пробелы или что-то еще до размер файла кратен длине записи.

А вот и мои результаты:

gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3 на x86-64

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
From what I can say with my puny test cases, you are 78% mainstream
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

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


«Можно делать что-либо с переменной-указателем. Оно должно содержать допустимое значение указателя, только если вы разыменовали его».

void noop(void *p); /* A no-op function that the compiler doesn't know to optimize away */
int main () {
    char *p = malloc(1);
    free(p);
    noop(p); /* may crash in implementations that verify pointer accesses */
    noop(p - 42000); /* and if not the previous instruction, maybe this one */
}

То же самое с целочисленными типами и типами с плавающей запятой (кроме unsigned char), которым разрешено иметь представления прерываний.


"Целочисленные вычисления обернуты вокруг. Таким образом, эта программа печатает большое отрицательное целое число."

#include <stdio.h>
int main () {
    printf("%d\n", INT_MAX+1); /* may crash due to signed integer overflow */
    return 0;
}

(только C89.) "Это нормально, если вы опустите конец main."

#include <stdio.h>
int main () {
    puts("Hello.");
} /* The status code is 7 on many implementations. */
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Включите проверку на целочисленные размеры.    Большинство людей предполагают, что int    больше чем короткий больше чем    голец. Тем не менее, все это может быть    false: sizeof(char) < sizeof(int); sizeof(short) < sizeof(int); sizeof(char) < sizeof(short)

Этот код может завершиться с ошибкой (происходит сбой при выравнивании)

unsigned char buf[64];

int i = 234;
int *p = &buf[1];
*p = i;
i = *p;
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Несколько вещей о встроенных типах данных:

  • char и signed char на самом деле являются двумя разными типами (в отличие от int и signed int, которые относятся к тот же тип целого числа со знаком).
  • целые числа со знаком не обязаны использовать дополнение до двух. Дополнение и знак + величина также являются действительными представлениями отрицательных чисел. Это делает битовые операции с отрицательными числами определяемыми реализацией .
  • Если вы назначите целое число вне диапазона для целочисленной переменной со знаком, поведение будет определено реализацией .
  • В C90 -3/5 может вернуть 0 или -1. Округление до нуля в случае, если один операнд был отрицательным, гарантируется только в C99 вверх и в C ++ 0x вверх.
  • Точных размеров для встроенных типов не существует. Стандарт охватывает только минимальные требования, такие как int имеет не менее 16 бит, а long имеет не менее 32 бита, a long long имеет не менее 64 бита. float может по меньшей мере правильно представить 6 наиболее значимых десятичных цифр. double может по меньшей мере правильно представить 10 наиболее значимых десятичных цифр.
  • IEEE 754 не является обязательным для представления чисел с плавающей запятой.

Конечно, на большинстве машин у нас будет два дополнения и IEEE 754 с плавающей точкой.

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

РЕДАКТИРОВАТЬ: обновлено до последней версии программы

Solaris SPARC-

gcc 3.4.6 в 32-битной версии

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 72% mainstream

gcc 3.4.6 в 64-битной версии

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 68% mainstream

и с SUNStudio 11 32 бит

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
From what I can say with my puny test cases, you are 79% mainstream

и с SUNStudio 11 64 bit

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
From what I can say with my puny test cases, you are 75% mainstream
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Как насчет этого:

Указатель на данные никогда не может совпадать с указателем на действительную функцию.

Это ИСТИНА для всех плоских моделей, моделей MS-DOS TINY, LARGE и HUGE, false для модели MS-DOS SMALL и почти всегда false для моделей MEDIUM и COMPACT (в зависимости от адреса загрузки вам понадобится действительно старый DOS, чтобы сделать это правдой).

Я не могу написать тест для этого

И еще хуже: указатели, приведенные к ptrdiff_t, можно сравнить. Это не относится к модели MS-DOS LARGE (единственное различие между LARGE и HUGE в том, что HUGE добавляет код компилятора для нормализации указателей).

Я не могу написать тест, потому что среда, в которой эта мощная бомба не будет выделять буфер размером более 64 КБ, поэтому код, демонстрирующий его, будет аварийно завершать работу на других платформах.

Этот конкретный тест будет проходить на одной ныне несуществующей системе (обратите внимание, что это зависит от внутренних компонентов malloc):

  char *ptr1 = malloc(16);
  char *ptr2 = malloc(16);
  if ((ptrdiff_t)ptr2 - 0x20000 == (ptrdiff_t)ptr1)
      printf("We like to think that unrelated pointers are equality comparable when cast to the appropriate integer, but they're not.");
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Вы можете использовать текстовый режим (fopen("filename", "r")) для чтения любого текстового файла.

Хотя это должно в теории работать нормально, если вы также используете ftell() в своем коде, и Ваш текстовый файл имеет окончания строк в стиле UNIX, в некоторых версиях стандартной библиотеки Windows ftell() часто возвращает недопустимые значения. Решение состоит в том, чтобы вместо этого использовать двоичный режим (fopen("filename", "rb")).

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

gcc 3.3.2 в AIX 5.3 (да, нам нужно обновить gcc)

We like to think that:
..04 a char is signed
   but 'CHAR_MIN==SCHAR_MIN' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits come always first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..16 malloc()=NULL means out of memory
   but '(malloc(0)!=NULL)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 71% mainstream
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Предположение, что некоторые могут сделать в C ++, состоит в том, что struct ограничивается тем, что он может делать в C. Факт в том, что в C ++ struct похож на class за исключением того, что по умолчанию все общедоступно.

C ++ struct:

struct Foo
{
  int number1_;  //this is public by default


//this is valid in C++:    
private: 
  void Testing1();
  int number2_;

protected:
  void Testing2();
};
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Стандартные математические функции в разных системах не дают одинаковых результатов.

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Visual Studio Express 2010 в 32-разрядной версии x86.

Z:\sandbox>cl testtoy.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

testtoy.c
testtoy.c(54) : warning C4293: '<<' : shift count negative or too big, undefined
 behavior
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:testtoy.exe
testtoy.obj

Z:\sandbox>testtoy.exe
We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Через Codepad.org (C++: g++ 4.1.2 flags: -O -std=c++98 -pedantic-errors -Wfatal-errors -Werror -Wall -Wextra -Wno-missing-field-initializers -Wwrite-strings -Wno-deprecated -Wno-unused -Wno-non-virtual-dtor -Wno-variadic-macros -fmessage-length=0 -ftemplate-depth-128 -fno-merge-constants -fno-nonansi-builtins -fno-gnu-keywords -fno-elide-constructors -fstrict-aliasing -fstack-protector-all -Winvalid-pch).

Обратите внимание, что на Codepad не было stddef.h. Я удалил тест 9 из-за кодовой панели, использующей предупреждения как ошибки. Я также переименовал переменную count, так как по какой-то причине она уже была определена.

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
From what I can say with my puny test cases, you are 84% mainstream
ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

Как насчет смещения вправо на чрезмерные суммы - это разрешено стандартом или стоит проверить?

Стандарт C определяет поведение следующей программы:

void print_string (char * st)
{
  char ch;
  while ((ch = * st ++)! = 0)
    Putch (ч); /* Предположим, что это определено * /
}
int main (void)
{
  print_string ( "Hello");
  вернуть 0;
}

По крайней мере на одном используемом мной компиляторе этот код не будет работать, если аргумент print_string не является "char const *". Допускает ли стандарт такое ограничение?

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

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11
0

К вашему сведению, для тех, кто должен перевести свои навыки C на Java, вот несколько ошибок.

EXPECT("03 a char is 8 bits",CHAR_BIT==8);
EXPECT("04 a char is signed",CHAR_MIN==SCHAR_MIN);

В Java char является 16-битным и подписанным. байт 8-битный и подписанный.

/* not true for Windows-64 */
EXPECT("05a long has at least the size of pointers",sizeof(long)>=sizeof(void*));

long всегда 64-битный, ссылки могут быть 32-битными или 64-битными (если у вас больше чем приложение с более чем 32 ГБ) 64-битные JVM обычно используют 32-битные ссылки.

EXPECT("08 overshifting is okay",(1<<bits_per_int)==0);
EXPECT("09 overshifting is *always* okay",(1<<BITS_PER_INT)==0);

Сдвиг маскируется таким образом, чтобы я <<64 == i == i <<-64, <<63 == я <<-1

EXPECT("13 The smallest bits always come first",(t=0x1234,0x34==*(char*)&t));

ByteOrder.nativeOrder () может быть BIG_ENDIAN или LITTLE_ENDIAN

EXPECT("14 i++ is strictly left to right",(i=0,a[i++]=i,a[0]==1));

i = i++ никогда не меняется i

/* suggested by David Thornley */
EXPECT("17 size_t is unsigned int",sizeof(size_t)==sizeof(unsigned int));

Размер коллекций и массивов всегда является 32-разрядным независимо от того, является ли JVM 32-разрядной или 64-разрядной.

EXPECT("19-1 char<short",sizeof(char)<sizeof(short));
EXPECT("19-2 short<int",sizeof(short)<sizeof(int));
EXPECT("19-3 int<long",sizeof(int)<sizeof(long));

char 16-битный, short 16-битный, int 32-битный и long 64-битный.

ответил Crafter0800 9 +04002014-10-09T13:10:11+04:00312014bEurope/MoscowThu, 09 Oct 2014 13:10:11 +0400 2014, 13:10:11

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132