Що належить до навчального інструменту для демонстрації необґрунтованих припущень, які люди висловлюють на C / C ++?


121

Я хотів би підготувати невеликий навчальний інструмент для ПЗ, який повинен допомогти початківцям (і проміжним) програмістам розпізнати та оскаржити свої необґрунтовані припущення на 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;
}

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

ОНОВЛЕННЯ Дякуємо за ваш внесок. Я додав кілька випадків із ваших відповідей і побачу, чи зможу я створити github для цього, як запропонував Грег.

ОНОВЛЕННЯ : Я створив для цього github repo, файл "gotcha.c":

Будь ласка, відповідайте тут патчами чи новими ідеями, щоб їх можна було обговорити чи уточнити тут. Я злитлю їх у gotcha.c тоді.


7
Розглянемо середню модель в DOS. Функції можна зберігати в декількох сегментах, тому вказівник функції має 32 біти. Але ваші дані зберігаються лише в одному сегменті, тому вказівники даних мають довжину лише 16 біт. Оскільки void * - покажчик даних, він шириною 16 біт, тому ви не можете помістити вказівник функції в один. Дивіться c-jump.com/CIS77/ASM/Directives/D77_0030_models.htm .
Девід Дано

6
Можливо, ви могли б підкинути цей код на github.com чи щось таке, і тоді люди могли легко внести виправлення.
Грег Хьюгілл

1
Багато чого тут має допомогти: stackoverflow.com/questions/367633/…
Martin York

4
POSIX вимагає, щоб покажчики функцій мали те саме представлення, що і void *, і можуть бути перетворені (з накидом) без втрати інформації. Однією з причин цього є dlsym()повернення порожнечі *, але призначене як для даних, так і для функціональних покажчиків. Тому може бути не так вже й погано залежати від цього.
jilles

3
@tristopia: Точка 15 тут є, тому що багато початківців часто дивуються, дізнавшись, що дані не пакуються постійно, а натомість вирівнюються до певних меж. Вони спантеличені, коли змінюють порядок членів і отримують різні розміри об'єкта. Також упаковка - це режим за замовчуванням для багатьох сучасних мікроконтролерів або вбудованих пристроїв. Мій вихід AVR Atmega та TurboC / MSDOS також упакований. MSDOS все ще використовується в промислових додатках.
Північна мейнфрейм

Відповіді:


91

Порядок оцінки підекспресій, у т.ч.

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

це вибрано

Наприклад

  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;
  } 

1
Я завжди знав це про параметри функцій, але я ніколи не думав про це з точки зору операторів ... ... і якщо я коли-небудь побачу, як ти пишеш такий код у виробничому середовищі, я поб'ю тебе мокрою локшиною.
riwalk

3
@Billy: Але лише для примітивних версій операторів.
Dennis Zickefoose

1
@Dennis: Це правда. (Ось чому це елемент в Ефективний / Більш Ефективний C ++, щоб ніколи не перевантажувати це (якщо ви не пишете boost::spirit)
Billy ONeal

1
@Daniel: Я не впевнений, що ти намагаєшся сказати. Здається, ви пропонуєте нормально перевантажувати операторів, тому що лише користувачі вашого класу можуть помилитися, і якщо ви не пишете прямо на C ++, це не має значення. Жоден з яких взагалі не має сенсу.
Dennis Zickefoose

2
@ user420536: поведінка просто не визначено, але не визначено. Так, приклад може надрукувати або Hello World! або Світ! Привіт, але це просто не визначено, оскільки порядок оцінки операндів +оператора не визначений (авторам компілятора не потрібно документувати поведінку). Він не порушує жодного правила точок послідовності як такого.
Prasoon Saurav

38

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 збоїв. "O_O"


gcc 4.4@x86_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 4.4@x86_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 2.7@x86_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 4.2.3@x86_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 11.1@x86_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 / Мала пам'ять

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 / Компактна пам'ять

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 (віце-емулятор)

alt текст


Я буду оновлювати їх пізніше:


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

CL + Visual Studio Express 2010 C ++ CLR, Windows 7 64bit

(повинен бути складений як 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


32
І ви визначили ще одне припущення: ви можете помістити 80 символів на термінальній лінії.
Майк Сеймур

3
sizeof(void*)>=sizeof(void(*)())буде більш релевантним, ніж ==. Нас нас цікавить лише те, "чи можемо ми зберегти функцію вказівника в недійсному вказівнику", тому припущення, яке вам потрібно перевірити, - чи void*є принаймні великим, як покажчик функції.
jalf

1
Якщо ваше середовище сумісне з POSIX, вам слід добре відповідати sizeof(void*)>=sizeof(void(*)())- див. Opengroup.org/onlinepubs/009695399/functions/dlsym.html
Daniel Earwicker

26

Дуже давно я викладав С із підручника, який мав

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

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


7
+1 для вказівки на одну з найпоширеніших і часто недооцінених помилок подібного роду.
R .. GitHub СТОП ДОПОМОГАЄТЬСЯ

4
Це також відбувається в 64-бітних системах, де size_t - 64 біт, а ints майже завжди коротший. Win64 все ще більш дивний, тому що size_t є unsigned long longтам. Додано як тест 17.
Північна мейнфрейм

На жаль, C час роботи Microsoft не підтримує zмодифікатор для size_tрозмірів цілих чисел, а long longтакож не підтримується на деяких платформах. Таким чином, немає жодного безпечного портативного способу форматування або відтворення друкованого розміру об'єкта.
Філ Міллер

15

Вам потрібно включити ++і --припущення, які роблять люди.

a[i++]= i;

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

Будь-яке твердження, що має ++(або --) та змінну, яка виникає не один раз, є проблемою.


І це просто таке поширене питання!
Матьє М.

8

Дуже цікаво!

Інші речі, які я думаю про це, можуть бути корисними для перевірки:

  • чи функціонують покажчики та покажчики даних в одному адресному просторі? (Порушення в Гарвардській архітектурних машинах, як малий режим DOS. Не знаю, як би ви протестували це.)

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

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

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

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

Редагувати: Додано кілька уточнюючих посилань на відмінний C FAQ.


2
До речі, деякий час назад я зробив експериментальний проект під назвою Clue ( cluecc.sourceforge.net ), який дозволив вам компілювати C у Lua, Javascript, Perl, LISP тощо. Це безжально використовувало невизначене поведінку у стандарті C, щоб змусити покажчики працювати . Це може бути цікаво спробувати цей тест на ньому.
Девід Дано

1
IIRC C дозволяє збільшити покажчик на 1 за межі кінця об'єкта, але не далі. Однак припускати його до положення перед початком об'єкта не дозволяється.
R .. GitHub СТОП ДОПОМОГАЄТЬСЯ

@R. Те саме в C ++. І додаткове збільшення може порушитися, якщо збільшення покажчика спричинить переповнення, на процесорі якого не просто трактуються покажчики як цілі числа.
jalf

5

Я думаю, вам слід докласти зусиль, щоб розрізнити два дуже різні класи "неправильних" припущень. Хороша половина (розширення правого зсуву та знаків, кодування, сумісне з ASCII, пам'ять лінійне, вказівники даних і функцій сумісні тощо) є досить обґрунтованими припущеннями для більшості кодерів С, які можуть бути , і навіть можуть бути включені до складу стандарту якби C розробляли сьогодні, і якби у нас не було застарілого базіка IBM Інша половина (речі, пов'язані з псевдонімом пам'яті, поведінкою функцій бібліотеки, коли пам'ять вводу та виводу перекривається, 32-бітні припущення, як, що вказують вказівникиint або які ви можете використовуватиmalloc без прототипу, що умова виклику є ідентичною для варіативних та не варіантних функцій, ...) або конфліктує з оптимізаціями, які сучасні компілятори хочуть виконати, або з міграцією на 64-бітні машини чи іншу нову технологію.


це не лише "барахло IBM" (хоча я згоден, що речі IBM - це сміття). У багатьох вбудованих системах сьогодні є подібні проблеми.
rmeador

Для уточнення, використання mallocбез прототипу означає не включення <stdlib.h>, що призводить mallocдо замовчування int malloc(int), ні-ні, якщо ви хочете підтримувати 64-розрядні.
Joey Adams

Технічно ви можете не включати <stdlib.h> тих пір, поки не включите інший заголовок, який визначає, size_tа потім ви самі заявите mallocправильний прототип.
R .. GitHub СТОП ДОПОМОГАЄТЬСЯ

5

Ось такий веселий: Що не так з цією функцією?

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' (бути 'pune' бути 'fubeg') va in_net! Naq gur pbzcvyre vf erdhverq abg gb gerng guvf nf n pbzcvyr-gvzr reebe. (TPP qbrf rzvg n jneavat, gubhtu.)]


О, це добре. clang 2.7 їсть це і створює повну дурницю без попередження.
Північна мейнфрейм

va_arg розширюється, якщо це макрос, а цикл while виконує лише перший вислів, можливо, багатьох?
Майстер

Ні (якщо це сталося, це було б помилкою в реалізації).
zwol

5
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

Я фактично бачив код, який поєднується pow(2, n)з бітовими операціями.
dan04

4

Деякі з них не можуть бути легко протестовані зсередини 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. */

2
Як конкретний приклад: при компіляції з gcc -ftrapv -Oрезультату We like to think that:слідує результатAborted
caf

@caf: "Цей параметр генерує пастки для підписаного переповнення при операціях додавання, віднімання та множення." Приємно знати, дякую.
Жил "ТАК - перестань бути злим"

1
Останнє також добре в C ++ (98, 03 і 0x), і неявно повертає 0.
jalf

Що погано, тому що попередній ANSI C це дозволяв, а також C99.
Джошуа

@Joshua: AFAIK немає різниці між попередньою ANSI C і C89 при поверненні mainбез значення: програма правильна, але повертає невизначений статус припинення (C89 §2.1.2.2). З багатьма реалізаціями (такими як gcc та старіші компілятори unix) ви отримуєте те, що було в певному реєстрі на той момент. Програма, як правило, працює до тих пір, поки не буде використана в makefile або іншому середовищі, яке перевіряє стан припинення.
Жил "ТАК - перестань бути злим"

4

Добре, що класичні припущення щодо переносимості поки не мають значення

  • припущення щодо розміру інтегральних типів
  • витривалість

4
"Ендіанство", включаючи "Є ендіанство": є машини середнього рівня, і стандарт дозволяє дивні речі, такі як зберігання shortзначення fedcab9876543210 (це 16 двійкових цифр), як два байти 0248ace і fdb97531.
Жил "ТАК - перестань бути злим"

так, ендіас напевно включає змішаний / середній ендіан, а також великий і малий. якщо ви переходите на спеціальне обладнання, у вас може виникнути будь-яка завзятість, яка вам подобається, на будь-якій шині.
jk.

Середній ендіан відомий як PDP endian. Жил декларує щось ще більш дивне, хоча це може спричинити головні болі від впровадження TCP / IP.
Джошуа

@Gilles: середній ендіанець ... Я дуже радий, що не розвиваюся на цьому. (але зараз мене попросять зробити мережевий проект середнього рівня, я впевнений) ...
Пол Натан

ARM FPE використовував парні середні ендіанці, де вони зберігалися як пара <high ​​quad> <low quad>, але впорядкування бітів у кожному квадратику було неправильним. (На щастя, ARM VFP вже не робить цього.)
Девід Даний

4
  • Помилки дискретизації через подання з плаваючою комою. Наприклад, якщо ви використовуєте стандартну формулу для вирішення квадратичних рівнянь, або кінцеві різниці наближених похідних, або стандартну формулу для обчислення дисперсій, точність втрачається через обчислення різниць між однаковими числами. Алгоритм Гауса для розв’язання лінійних систем поганий, тому що накопичуються помилки округлення, таким чином, використовується декомпозиція QR або LU, розклад Холеського, SVD тощо. Додавання чисел з плаваючою комою не асоціативно. Є деннормальні, нескінченні та NaN значення. a + b - ab .

  • Рядки: різниця між символами, кодовими точками та одиницями коду. Як Unicode реалізований у різних операційних системах; Кодування Unicode. Відкриття файлу з довільним іменем файлу Unicode неможливо за допомогою C ++ переносним способом.

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

  • ERROR_SUCCESS = 0


4

Додайте чек на цілі розміри. Більшість людей припускають, що інт більший, ніж короткий, більший від знака. Однак, все це може бути помилковим: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;

чи не вдасться цей код у C ++? IIRC, не забороняється вводити покажчики між непов'язаними типами, ВКЛЮЧИТИ для char *, які можна передавати на будь-який тип (чи це навпаки?).
rmeador

1
Ви можете просто зробити int *p = (int*)&buf[1];в C ++, люди очікують, що це також працюватиме.
NOS

@nos, так, це може вийти з ладу, але помилка - збій, тому його програма не може перевірити цю програму. :(
Джошуа

1
sizeof(char) < sizeof(int)необхідно. Наприклад, fgetc () повертає значення символу у вигляді неподписаного знака, перетвореного в int, або EOFяке є негативним значенням. unsigned charможе не мати оббивних шматочків, тому єдиний спосіб зробити це - зробити int більшим, ніж char. Також (у більшості версій) специфікація C вимагає, щоб будь-яке значення з діапазону -32767..32767 могло бути збережене в int.
jilles

@illes все ще є DSP з 32 бітовими символами та 32 бітовими входами.
NOS

3

Кілька речей про вбудовані типи даних:

  • charі signed charнасправді є двома різними типами (на відміну від них intі signed intякі відносяться до одного і того ж підписаного цілого типу).
  • підписані цілі числа не потрібно використовувати доповнення двох. Доповнення Онеса та знак + величина також є дійсними поданнями від’ємних чисел. Це робить бітові операції, пов’язані з реалізацією негативних чисел .
  • Якщо призначити ціле число поза діапазоном підписаній цілій змінній, поведінка визначається реалізацією .
  • У C90 -3/5могли повернутися 0або -1. Округлення до нуля у випадку, якщо один операнд був негативним, гарантується лише у C99 вгору та C ++ 0x вгору.
  • Не існує точних гарантій розміру для вбудованих типів. Стандарт поширюється тільки мінімальні вимоги , такі як intмає по крайней мере , 16 біт, A longмає по крайней мере , 32 біта, A long longмає по крайней мере , 64 біта. A floatможе принаймні правильно представляти 6 найбільш значущих десяткових цифр. Аdouble може принаймні правильно представляти 10 найбільш значущих десяткових цифр.
  • IEEE 754 не є обов'язковим для представлення чисел з плаваючою комою.

Правда, на більшості машин у нас буде два доповнення та IEEE 754.


Цікаво, яке значення має призначення цілих цільових призначень, що визначаються реалізацією, а не невизначеною поведінкою? На деяких платформах така вимога змусить компілятор генерувати додатковий код для int mult(int a,int b) { return (long)a*b;}[наприклад, якщо intце 32 біта, але реєструється і longє 64]. Без такої вимоги "природна" поведінка найшвидшого впровадження long l=mult(1000000,1000000);встановила б lрівне 1000000000000, хоча це "неможливе" значення для int.
supercat

3

Як щодо цього:

Жоден покажчик даних ніколи не може бути таким, як дійсний вказівник функції.

Це ПРАВИЛЬНА для всіх плоских моделей, моделей MS-DOS TINY, LARGE та HUGE, хибна для моделей MS-DOS SMALL і майже завжди хибна для моделей MEDIUM і COMPACT (залежить від адреси завантаження, вам знадобиться дійсно старий DOS для зробити це правдою).

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

І ще гірше: вказівники, передані на ptrdiff_t, можна порівняти. Це не вірно для великої моделі MS-DOS (Єдина відмінність LARGE від ВЕЛИЧЕЗНОГО полягає в тому, що ВЕЛІЧНЕ додає код компілятора для нормалізації покажчиків).

Я не можу написати тест, оскільки середовище, де ці бомби важко, не виділить буфер, більший за 64K, так що код, який демонструє, зазнав аварії на інших платформах.

Цей конкретний тест пройшов би в одній теперішній системі, яка вже не працює (зауважте, це залежить від внутрішнього середовища 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.");

3

EDIT: Оновлено до останньої версії програми

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 біт

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

2

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

Хоча теоретично це має спрацювати нормально, якщо ви також використовуєте ftell()свій код, а ваш текстовий файл має рядкові закінчення у стилі UNIX, у деяких версіях стандартної бібліотеки Windows ftell()часто повертаються недійсні значення. Рішення - використовувати двійковий режим замість ( fopen("filename", "rb")).


1

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

1

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

С ++ структура:

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


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

protected:
  void Testing2();
};

1

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


1

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

1

Через 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

1

Як щодо зрушення вправо на надмірну кількість - це дозволено стандартом, чи варто тестувати?

Чи визначає стандарт C поведінку наступної програми:

недійсний print_string (char * st)
{
  char ch;
  while ((ch = * st ++)! = 0)
    путч (ч); / * Припустимо, що це визначено * /
}
int main (пустота)
{
  print_string ("Привіт");
  повернути 0;
}

Щонайменше в одному компіляторі, який я використовую, цей код не вдасться, якщо аргумент print_string не буде "char const *". Чи допускає стандарт таке обмеження?

Деякі системи дозволяють виробляти покажчики на неприєднані 'int', а інші - ні. Можливо, варто перевірити.


C89 §3.3.7: "Якщо значення правого операнда від'ємне або більше або дорівнює ширині в бітах промотованого лівого операнда, поведінка не визначена." (стосується як <<і >>). C99 має ідентичну мову в §6.5.7-3.
Жил "ТАК - перестань бути злим"

Крім putch(чому ви не використовували стандарт putchar?), Я не бачу жодної визначеної поведінки у вашій програмі. C89 §3.1.4 вказує, що "літеральний рядок символів має […] тип" масив знаків "(примітка: ні const), і що" якщо програма намагається змінити літеральний рядок [...], поведінка не визначена " . Що таке компілятор, і як він перекладає цю програму?
Жил 'ТАК - перестань бути злим'

2
У константах символів C ++ не є символами [], вони є const char []. Однак ... там використовується , щоб бути певний отвір в системі типів , щоб дозволити вам використовувати постійну рядок в контексті , де символ * , як очікувалося , а не отримати помилку типу. Це призвело до ситуацій, коли print_string ("foo") буде працювати, але print_string ("foo" +0) не буде. Це було дуже заплутано, особливо в середовищах, де файли C збираються за допомогою типового компілятора C ++. Діра була видалена в нових компіляторах, але все ще є багато старих. AFAIK C99 як і раніше визначає рядкові константи як char [].
Девід Даний

1
У компіляторах HiTech для контролерів серії PIC Microchip вказівник без класифікатора пам'яті може вказувати лише на оперативну пам'ять. Покажчик, кваліфікований за const, може вказувати на RAM або ROM. Покажчики, які не відповідають вимогам конкурсу, відмічаються безпосередньо в коді; покажчики, які відповідають вимогам const, переносяться через звичайну бібліотеку. Залежно від конкретного типу PIC, покажчики без кваліфікації мають 1 або 2 байти; кваліфіковані по const - 2 або 3. Оскільки ПЗУ набагато більше, ніж ОЗУ, то константи в ПЗУ, як правило, хороша річ.
supercat

@David Дано: Зверніть увагу і на мій попередній коментар. Я вважаю за краще компілятори, які використовують класифікатори, крім "const", для позначення класу зберігання обладнання; у компілятора HiTech є кілька досить дратівливих примх із розподілом класу зберігання (наприклад, елементи даних, "розмір компонента" яких становить байт, або елементи даних, що перевищують 256 байт, переходять у "великий" сегмент. Інші елементи даних переходять у " bss "сегмент для модуля, який вони визначені; всі елементи" bss "в модулі повинні вміщуватися в межах 256 байт. Масиви, які трохи не перевищують 256 байт, можуть стати справжньою неприємністю.
supercat

0

FYI, Для тих, хто повинен перекласти свої навички 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*));

довгий завжди 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);

Зсув маскується так, що i << 64 == i == i << -64, i << 63 == i << -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-бітний, короткий - 16-розрядний, int - 32-розрядний, а довгий - 64-розрядний.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.