O que pertence a uma ferramenta educacional para demonstrar as suposições injustificadas que as pessoas fazem em C / C ++?


121

Eu gostaria de preparar uma pequena ferramenta educacional para SO, que deve ajudar programadores iniciantes (e intermediários) a reconhecer e desafiar suas suposições injustificadas em C, C ++ e suas plataformas.

Exemplos:

  • "números inteiros"
  • "todo mundo tem ASCII"
  • "Eu posso armazenar um ponteiro de função em um vazio *"

Imaginei que um pequeno programa de teste pudesse ser executado em várias plataformas, que executam as suposições "plausíveis" que, a partir de nossa experiência em SO, geralmente são feitas por muitos desenvolvedores mainstream inexperientes / semiexperientes e registram a maneira como eles quebram em diversas máquinas.

O objetivo disso não é provar que é "seguro" fazer algo (o que seria impossível de fazer, os testes provam qualquer coisa se eles quebrarem), mas demonstrar até mesmo ao indivíduo mais compreensivo como a expressão mais discreta quebrar em uma máquina diferente, se ela tiver um comportamento indefinido ou definido pela implementação. .

Para conseguir isso, gostaria de perguntar:

  • Como essa ideia pode ser melhorada?
  • Quais testes seriam bons e como eles deveriam ser?
  • Você executaria os testes nas plataformas nas quais você pode colocar as mãos e publicar os resultados, para que possamos terminar com um banco de dados de plataformas, como elas diferem e por que essa diferença é permitida?

Aqui está a versão atual do brinquedo de teste:

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

Ah, e eu criei este wiki da comunidade desde o início, porque achei que as pessoas querem editar minha tagarelice quando lêem isso.

ATUALIZAÇÃO Obrigado pela sua contribuição. Adicionei alguns casos de suas respostas e verei se posso configurar um github para isso, como Greg sugeriu.

UPDATE : Eu criei um repositório no Github para isso, o arquivo é "gotcha.c":

Responda aqui com correções ou novas idéias, para que possam ser discutidas ou esclarecidas aqui. Vou fundi-los em gotcha.c então.


7
Considere o modelo médio no DOS. As funções podem ser armazenadas em vários segmentos; portanto, um ponteiro de função tem 32 bits. Mas seus dados são armazenados apenas em um único segmento; portanto, os ponteiros de dados têm apenas 16 bits. Como o void * é um ponteiro de dados, possui 16 bits de largura, portanto você não pode encaixar um ponteiro de função em um. Consulte c-jump.com/CIS77/ASM/Directives/D77_0030_models.htm .
David Given

6
Talvez você possa lançar esse código no github.com ou algo assim e as pessoas possam contribuir com patches facilmente.
Greg Hewgill

1
Um monte de coisas aqui devem ajudar: stackoverflow.com/questions/367633/...
Martin Iorque

4
O POSIX exige que os ponteiros de função tenham a mesma representação que void * e possam ser convertidos (com conversão) sem perda de informações. Uma das razões para isso é que dlsym()retorna um nulo *, mas destina-se a indicadores de dados e funções. Portanto, pode não ser tão ruim depender disso.
Jilles

3
@tristopia: O ponto 15 está aqui, porque muitos iniciantes costumam se surpreender ao saber que os dados não são compactados continuamente, mas alinhados a certos limites. Eles ficam intrigados quando alteram a ordem dos membros e obtêm diferentes tamanhos de objetos. Além disso, a embalagem é o modo padrão com muitos microcontroladores ou dispositivos incorporados contemporâneos. Minha saída AVR Atmega e TurboC / MSDOS também está compactada. O MSDOS ainda é usado em aplicações industriais.
Mainframe Nórdico

Respostas:


91

A ordem de avaliação das subexpressões, incluindo

  • os argumentos de uma chamada de função e
  • operandos de operadores (por exemplo, +, -, =, *, /), com a excepção de:
    • os operadores lógicos binários ( &&e ||),
    • o operador condicional ternário ( ?:) e
    • o operador de vírgula ( ,)

é não especificado

Por exemplo

  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
Eu sempre soube disso sobre parâmetros de função, mas nunca pensei nisso em termos de operadores ... ... e se eu vir você escrevendo um código assim em um ambiente de produção, vou lhe dar um tapa com um macarrão molhado.
riwalk

3
@ Billy: Mas apenas para as versões primitivas dos operadores.
Dennis Zickefoose

1
@ Dennis: Isso é verdade. (Que é por isso que é um item em Effective / MoreEffective C ++ não sobrecarregar aqueles (A menos que você está escrevendo boost::spirit)
Billy ONeal

1
@ Daniel: Eu não tenho certeza do que você está tentando dizer. Parece que você está sugerindo que não há problema em sobrecarregar os operadores, porque são apenas os usuários da sua classe que podem errar, e se você não está escrevendo em C ++ direto, isso não importa. Nenhum dos quais faz qualquer sentido.
Dennis Zickefoose

2
@ user420536: O comportamento é apenas não especificado, mas não indefinido. Sim, o exemplo pode imprimir Hello World! ou mundo! Olá, mas isso não é especificado porque a ordem de avaliação dos operandos do +operador não é especificada (os escritores do compilador não precisam documentar o comportamento). Não viola nenhuma regra de ponto de sequência como tal.
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 trava. "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 / Memória pequena

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 / Memória Média

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

Memória Turbo C ++ / DOS / Compacta

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 (vice-emulador)

texto alternativo


Vou atualizá-los mais tarde:


Borland C ++ Builder 6.0 no 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 de 64 bits

(deve ser compilado como C ++ porque o compilador CLR não suporta C puro)

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 (pré -elas 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

O Windows de 64 bits usa o modelo LLP64: Ambos inte longsão definidos como 32 bits, o que significa que nenhum é longo o suficiente para um ponteiro.


avr-gcc 4.3.2 / ATmega168 (Arduino Diecimila)

As suposições com falha são:

..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

O Atmega168 possui um PC de 16 bits, mas o código e os dados estão em espaços de endereço separados. Atmegas maiores têm um PC de 22 bits !.


gcc 4.2.1 no MacOSX 10.6, compilado com -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
E você identificou outra suposição: que você pode ajustar 80 caracteres em uma linha terminal.
Mike Seymour

3
sizeof(void*)>=sizeof(void(*)())seria mais relevante que ==. Tudo o que nos preocupa é "podemos armazenar um ponteiro de função em um ponteiro nulo", então a suposição que você precisa testar é se a void*é pelo menos tão grande quanto um ponteiro de função.
jalf

1
Se o ambiente é compatível com POSIX, você deve estar bem com sizeof(void*)>=sizeof(void(*)())- ver opengroup.org/onlinepubs/009695399/functions/dlsym.html
Daniel Earwicker

26

Há muito tempo, eu estava ensinando C de um livro que tinha

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

como uma pergunta de amostra. Ele falhou para um aluno, porque sizeofgera valores do tipo size_t, não int, intnesta implementação tinha 16 bits e size_t32, e era big-endian. (A plataforma era o Lightspeed C em Macintoshes baseados em 680x0. Eu disse isso há muito tempo.)


7
+1 por apontar um dos erros mais comuns e geralmente esquecidos desse tipo.
R .. GitHub PARE DE AJUDAR O GELO

4
Isso também acontece em sistemas de 64 bits, em que size_t é de 64 bits e ints são quase sempre menores. O Win64 ainda é mais estranho, porque size_t está unsigned long longlá. Adicionado como Teste 17.
Nordic Mainframe

Infelizmente, o tempo de execução C da Microsoft não suporta o zmodificador para size_tnúmeros inteiros de tamanho e long longtambém não é suportado em algumas plataformas. Portanto, não há uma maneira portátil e segura de formatar ou converter o tamanho impresso de um objeto.
Phil Miller

15

Você precisa incluir os ++e --suposições que as pessoas fazem.

a[i++]= i;

Por exemplo, é sintaticamente legal, mas produz resultados variados, dependendo de muitas coisas para raciocinar.

Qualquer declaração que tenha ++(ou-- ) e uma variável que ocorra mais de uma vez é um problema.


E é apenas uma pergunta tão comum também!
Matthieu M.

8

Muito interessante!

Outras coisas em que posso pensar podem ser úteis para verificar:

  • existem indicadores de função e dados no mesmo espaço de endereço? (Quebras nas máquinas de arquitetura de Harvard, como o modo pequeno do DOS. Porém, não sei como você testaria isso.)

  • se você pegar um ponteiro de dados NULL e o converter no tipo inteiro apropriado, ele possui o valor numérico 0? (Quebra em algumas máquinas realmente antigas - consulte http://c-faq.com/null/machexamp.html .) O mesmo vale para o ponteiro de função. Além disso, eles podem ter valores diferentes.

  • incrementar um ponteiro após o final do seu objeto de armazenamento correspondente e, em seguida, voltar novamente, causa resultados razoáveis? (Eu não conheço nenhuma máquina na qual ele realmente interrompa, mas acredito que a especificação C não permite que você pense em ponteiros que não apontam para (a) o conteúdo de uma matriz ou (b) o elemento imediatamente após a matriz ou (c) NULL. Consulte http://c-faq.com/aryptr/non0based.html .)

  • comparar dois ponteiros com diferentes objetos de armazenamento com <e> produz resultados consistentes? (Eu posso imaginar essa quebra em máquinas exóticas baseadas em segmentos; as especificações proíbem essas comparações, para que o compilador tenha o direito de comparar apenas a parte deslocada do ponteiro, e não a parte do segmento.)

Hmm. Vou tentar pensar um pouco mais.

Edit: Adicionado alguns links de esclarecimento para o excelente C FAQ.


2
Aliás, um tempo atrás, eu fiz um projeto experimental chamado Clue ( cluecc.sourceforge.net ), que permitiu compilar C em Lua, Javascript, Perl, LISP, etc. Ele explorou implacavelmente o comportamento indefinido no padrão C para fazer os ponteiros funcionarem . Pode ser interessante tentar este teste nele.
David Given

1
O IIRC C permite incrementar um ponteiro em 1 além do final de um objeto, mas não mais. Decrementá-lo para uma posição antes do início de um objeto não é permitido, no entanto.
R .. GitHub Pare de ajudar o gelo

@R. O mesmo em C ++. E incrementar ainda mais pode ser interrompido se incrementar o ponteiro causar um estouro, nas CPUs, que não tratam apenas os ponteiros como números inteiros.
jalf

5

Eu acho que você deve fazer um esforço para distinguir entre duas classes muito diferentes de suposições "incorretas". Uma boa metade (deslocamento à direita e extensão de sinal, codificação compatível com ASCII, memória é linear, ponteiros de dados e funções são compatíveis etc.) são suposições bastante razoáveis ​​para a maioria dos codificadores C criar e podem até ser incluídas como parte do padrão se C estivesse sendo projetado hoje e se não tivéssemos o legado de sucata IBM herdado. A outra metade (coisas relacionadas ao alias de memória, comportamento das funções da biblioteca quando a memória de entrada e saída se sobrepõe, suposições de 32 bits como as que os ponteiros se encaixamint ou que você pode usarmalloc sem um protótipo, essa convenção de chamada é idêntica para funções variadas e não variadas, ...) conflitam com as otimizações que os compiladores modernos desejam executar ou com a migração para máquinas de 64 bits ou outra nova tecnologia.


não é apenas "IBM lixo" (embora eu concorde que o material da IBM seja lixo). Muitos sistemas embarcados hoje têm problemas semelhantes.
Rmeador

Para esclarecer, usar mallocsem protótipo significa não incluir <stdlib.h>, o que faz malloccom que o padrão seja int malloc(int)um não-não, se você deseja oferecer suporte a 64 bits.
Joey Adams

Tecnicamente, você é livre para não incluir <stdlib.h>, desde que inclua outro cabeçalho que defina size_te, em seguida, declare malloccom um protótipo correto.
R .. GitHub Pare de ajudar o gelo

5

Aqui está uma divertida: O que há de errado com esta função?

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

[Resposta (rot13): Inevnqvp nethzragf borl gur byq X&E cebzbgvba ehyrf, juvpu zrnaf lbh pnaabg hfr 'sybng (seja' pune 'seja' fubeg ') va in_net! Naq gur pbzcvyre vf erdhverq abg gb gerng guvf nf n pbzcvyr-gvzr reebe. (TPP qbrf rzvg n jneavat, gubhtu.)]


Oh, essa é boa. O clang 2.7 come isso e produz um completo disparate sem aviso.
Mainframe Nordic

va_arg se expande se for uma macro e o loop while executa apenas a primeira instrução, talvez de muitas?
Maister

Não (se isso acontecesse, seria um bug na implementação).
Zwol 30/08/10

5
EXPECT("## pow() gives exact results for integer arguments", pow(2, 4) == 16);

Outro é sobre o modo de texto no fopen. A maioria dos programadores assume que texto e binário são iguais (Unix) ou que o modo de texto adiciona \rcaracteres (Windows). Mas C foi portado para sistemas que usam registros de largura fixa, nos quais fputc('\n', file)em um arquivo de texto significa adicionar espaços ou algo até que o tamanho do arquivo seja múltiplo do comprimento do registro.

E aqui estão meus resultados:

gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3 no 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

Na verdade, eu vi código que combinava pow(2, n)com operações de bits.
dan04 23/09/10

4

Alguns deles não podem ser facilmente testados a partir do C, porque o programa provavelmente trava nas implementações em que a suposição não se aplica.


"Não há problema em fazer qualquer coisa com uma variável com valor de ponteiro. Ele só precisa conter um valor de ponteiro válido se você a derereçar."

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 */
}

O mesmo ocorre com os tipos de ponto flutuante e integral (que não sejam unsigned char), que podem ter representações de trap.


"Cálculos inteiros são contornados. Portanto, este programa imprime um número inteiro negativo grande."

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

(Somente C89.) "Não há problema em cair no final de main."

#include <stdio.h>
int main () {
    puts("Hello.");
} /* The status code is 7 on many implementations. */

2
Como um exemplo concreto: Quando compilado com gcc -ftrapv -O, a saída é We like to think that:seguida porAborted
caf

@caf: "Esta opção gera traps para estouro assinado em operações de adição, subtração e multiplicação." É bom saber, obrigado.
Gilles 'SO- stop be evil' (

1
O último é ok em C ++ (98, 03 e 0 x), bem como, e implicitamente retorna 0.
jalf

O que é desagradável porque o pré-ANSI C permitiu isso e o C99 também.
Joshua

@ Josué: AFAIK não há diferença entre pré-ANSI C e C89 ao retornar mainsem valor: o programa está correto, mas retorna um status de finalização indefinido (C89 §2.1.2.2). Com muitas implementações (como gcc e compiladores unix mais antigos), você obtém o que estava em um determinado registro naquele momento. O programa normalmente funciona até ser usado em um makefile ou outro ambiente que verifica o status da finalização.
Gilles 'SO- stop be evil' (

4

Bem, as suposições clássicas de portabilidade ainda não mencionadas são

  • suposições sobre tamanho de tipos integrais
  • endianness

4
"Endianness", incluindo "Existe um endianness": existem máquinas da middleian, e o padrão permite coisas estranhas, como armazenar um shortvalor fedcab9876543210 (com 16 dígitos binários) como os dois bytes 0248ace e fdb97531.
Gilles 'SO- stop being evil' (

sim endianess com certeza inclui endian misto / médio, além de grande e pequeno. se você for para um hardware personalizado, poderá ter qualquer endianess que desejar em qualquer barramento.
jk.

Endian médio é conhecido como PDP endian. Gilles descreve algo ainda mais estranho, o que causaria dores de cabeça na implementação do TCP / IP.
Joshua

@ Gilles: middle-endian ... Estou muito feliz por não estar desenvolvendo esse. (mas agora eu vou me pediu para fazer um projeto de rede de meia-endian, tenho certeza) ...
Paul Nathan

O ARM FPE usava dobros médio-endianos, onde eram armazenados como um par <alto quad> <baixo quad>, mas a ordem dos bits dentro de cada quadra era inversa. (Felizmente, ARM VFP não mais fazer isso.)
David Dada

4
  • Erros de discretização devido à representação de ponto flutuante. Por exemplo, se você usar a fórmula padrão para resolver equações quadráticas, ou diferenças finitas para aproximar derivadas, ou a fórmula padrão para calcular variações, a precisão será perdida devido ao cálculo das diferenças entre números semelhantes. O algoritmo de Gauß para resolver sistemas lineares é ruim, porque os erros de arredondamento se acumulam; portanto, utiliza-se decomposição QR ou LU, decomposição de Cholesky, SVD etc. A adição de números de ponto flutuante não é associativa. Existem valores anormais, infinitos e NaN. a + b - ab .

  • Strings: diferença entre caracteres, pontos de código e unidades de código. Como o Unicode é implementado nos vários sistemas operacionais; Codificações Unicode. Abrir um arquivo com um nome de arquivo Unicode arbitrário não é possível com o C ++ de maneira portátil.

  • Condições de corrida, mesmo sem encadeamento: se você testar se existe um arquivo, o resultado poderá se tornar inválido a qualquer momento.

  • ERROR_SUCCESS = 0


4

Inclua uma verificação para tamanhos inteiros. A maioria das pessoas assume que um int é maior que um short e maior que um char. No entanto, tudo isso pode ser falso:sizeof(char) < sizeof(int); sizeof(short) < sizeof(int); sizeof(char) < sizeof(short)

Esse código pode falhar (falha no acesso não alinhado)

unsigned char buf[64];

int i = 234;
int *p = &buf[1];
*p = i;
i = *p;

esse código falharia em C ++? IIRC, é ilegal converter ponteiros entre tipos não relacionados, EXCETO para char *, que podem ser convertidos para qualquer tipo (ou é o contrário?).
Rmeador 11/08

1
Você poderia simplesmente fazer int *p = (int*)&buf[1];em c ++, as pessoas esperam que isso funcione também.
Nos

@nos, sim, isso pode falhar, mas a falha é travar, então seu programa não pode testar esse. :( #
Joshua Joshua

1
sizeof(char) < sizeof(int)É necessário. Por exemplo, fgetc () retorna o valor do caractere como um caractere não assinado convertido em int ou EOFque é um valor negativo. unsigned charpode não ter bits de preenchimento, então a única maneira de fazer isso é tornando int maior que char. Além disso, (a maioria das versões) das especificações C exigem que qualquer valor do intervalo -32767..32767 possa ser armazenado em um int.
Jilles

@illes ainda, existem DSPs com caracteres de 32 bits e entradas de 32 bits.
Nos

3

Algumas coisas sobre os tipos de dados internos:

  • char e signed char na verdade, são dois tipos distintos (diferentes inte signed intque se referem ao mesmo tipo inteiro assinado).
  • números inteiros assinados não precisam usar o complemento de dois. O complemento e a magnitude do sinal + também são representações válidas de números negativos. Isso torna as operações de bits que envolvem números negativos definidos pela implementação .
  • Se você atribuir um número inteiro fora do intervalo a uma variável inteira assinada, o comportamento será definido pela implementação .
  • Em C90, -3/5poderia retornar 0ou -1. O arredondamento para zero no caso de um operando ser negativo é garantido apenas em C99 para cima e C ++ 0x para cima.
  • Não há garantias de tamanho exato para os tipos internos. O padrão cobre apenas requisitos mínimos, como um intcom pelo menos 16 bits, um longcom pelo menos 32 bits e um long longcom pelo menos 64 bits. A floatpode pelo menos representar 6 dígitos decimais mais significativos corretamente. A doublepode pelo menos representar 10 dígitos decimais mais significativos corretamente.
  • O IEEE 754 não é obrigatório para representar números de ponto flutuante.

É certo que, na maioria das máquinas, teremos dois complementos e flutuadores IEEE 754.


Gostaria de saber qual o valor de ter atribuições inteiras fora do intervalo definidas pela implementação em vez de Comportamento indefinido? Em algumas plataformas, esse requisito forçaria o compilador a gerar código extra para int mult(int a,int b) { return (long)a*b;}[por exemplo, se intfor de 32 bits, mas registra e longé de 64]. Sem esse requisito, o comportamento "natural" da implementação mais rápida de long l=mult(1000000,1000000);seria ligual a 1000000000000, mesmo que seja um valor "impossível" para um int.
Supercat

3

Que tal este:

Nenhum ponteiro de dados pode ser o mesmo que um ponteiro de função válido.

Isso é VERDADEIRO para todos os modelos simples, modelos MS-DOS TINY, LARGE e HUGE, falso para o modelo SM-DOS SMALL e quase sempre falso para os modelos MÉDIO e COMPACTO (depende do endereço de carregamento, você precisará de um DOS realmente antigo). faça verdade).

Não posso escrever um teste para isso

E pior: os ponteiros convertidos para ptrdiff_t podem ser comparados. Isso não é verdade para o modelo MS-DOS LARGE (a única diferença entre LARGE e HUGE é HUGE adiciona código do compilador para normalizar os ponteiros).

Não consigo escrever um teste porque o ambiente em que essa bomba é difícil não aloca um buffer maior que 64K, portanto o código que a demonstra falha em outras plataformas.

Esse teste em particular passaria em um sistema agora extinto (observe que depende dos elementos internos do 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: Atualizado para a última versão do programa

Solaris-SPARC

gcc 3.4.6 em 32 bits

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 em 64 bits

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

e com o SUNStudio 11 de 32 bits

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

e com o SUNStudio 11 de 64 bits

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

Você pode usar o modo de texto ( fopen("filename", "r")) para ler qualquer tipo de arquivo de texto.

Embora isso , em teoria, funcione bem, se você também usar ftell()no seu código e seu arquivo de texto tiver terminações de linha no estilo UNIX, em algumas versões da biblioteca padrão do Windows, ftell()retornará frequentemente valores inválidos. A solução é usar o modo binário ( fopen("filename", "rb")).


1

gcc 3.3.2 no AIX 5.3 (sim, precisamos atualizar o 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

Uma suposição de que alguns podem fazer em C ++ é que a structé limitado ao que pode fazer em C. O fato é que, em C ++, a structé como a classexceto que tem tudo público por padrão.

Estrutura C ++:

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


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

protected:
  void Testing2();
};

1

As funções matemáticas padrão em sistemas diferentes não fornecem resultados idênticos.


1

Visual Studio Express 2010 em x86 de 32 bits.

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

Via 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).

Observe que o Codepad não possui stddef.h. Eu removi o teste 9 devido ao codepad usando avisos como erros. Também renomei a countvariável, pois ela já estava definida por algum motivo.

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

Que tal mudar de posição em quantidades excessivas - isso é permitido pelo padrão ou vale a pena testar?

O Padrão C especifica o comportamento do seguinte programa:

void print_string (char * st)
{
  char ch;
  while ((ch = * st ++)! = 0)
    putch (ch); / * Suponha que isso esteja definido * /
}
int main (vazio)
{
  print_string ("Olá");
  retornar 0;
}

Em pelo menos um compilador que eu uso, esse código falhará, a menos que o argumento para print_string seja um "char const *". O padrão permite tal restrição?

Alguns sistemas permitem produzir indicadores para int desalinhados e outros não. Pode valer a pena testar.


C89 §3.3.7: “Se o valor do operando direito for negativo ou for maior ou igual à largura em bits do operando esquerdo promovido, o comportamento será indefinido.” (aplica-se a ambos <<e >>). C99 possui linguagem idêntica em §6.5.7-3.
Gilles 'SO- stop be evil'

Além de putch(por que você não usou o padrão putchar?), Não vejo nenhum comportamento indefinido no seu programa. C89 §3.1.4 especifica que “um literal de cadeia de caracteres tem […] o tipo 'array of char'” (nota: no const) e que “se o programa tentar modificar um literal de cadeia de caracteres […], o comportamento será indefinido” . Que compilador é esse e como ele traduz esse programa?
Gilles 'SO- stop be evil'

2
No C ++, as constantes de caracteres não são char [], são const char []. No entanto ... costumava haver um furo específico no sistema de tipos para permitir o uso de uma constante de cadeia de caracteres em um contexto em que um caractere * era esperado e não ocorria um erro de tipo. Isso levou a situações em que print_string ("foo") funcionaria, mas print_string ("foo" +0) não funcionaria. Isso foi profundamente confuso, principalmente em ambientes em que os arquivos C são compilados usando um compilador C ++ por padrão. O buraco foi removido em novos compiladores, mas ainda existem muitos antigos. O AFAIK C99 ainda define constantes de string como char [].
David Given

1
Nos compiladores HiTech para a série de controladores Microchip PIC, um ponteiro sem um qualificador de armazenamento pode apontar apenas para RAM. Um ponteiro qualificado de const pode apontar para RAM ou ROM. Ponteiros não qualificados pela const são desreferenciados diretamente no código; ponteiros qualificados pela const são desreferenciados através da rotina da biblioteca. Dependendo do tipo específico de PIC, os ponteiros não qualificados para const são de 1 ou 2 bytes; os qualificados com const são 2 ou 3. Como a ROM é muito mais abundante que a RAM, ter constantes na ROM geralmente é uma coisa boa.
Supercat

@ David dado: Observe o meu comentário anterior também. Prefiro compiladores que usem qualificadores diferentes de "const" para indicar a classe de armazenamento de hardware; o compilador HiTech possui algumas peculiaridades bastante irritantes com sua alocação de classe de armazenamento (por exemplo, itens de dados cujo "tamanho do componente" é um byte, ou itens de dados com mais de 256 bytes, entram em um segmento "grande". Outros itens de dados ficam em " bss" segmento para o módulo que está definido; todos os '' itens BSS em um módulo deve caber dentro de 256 bytes matrizes que são um pouco menos do que 256 bytes pode ser um incômodo real..
supercat

0

Para sua informação, para aqueles que precisam traduzir suas habilidades em C para Java, aqui estão algumas dicas.

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

Em Java, char é de 16 bits e assinado. byte é de 8 bits e assinado.

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

long é sempre de 64 bits, as referências podem ser de 32 ou 64 bits (se você tiver mais de um aplicativo com mais de 32 GB). As JVMs de 64 bits normalmente usam referências de 32 bits.

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

O deslocamento é mascarado para que i << 64 == i == i << -64, i << 63 == i << -1

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

ByteOrder.nativeOrder () pode ser BIG_ENDIAN ou LITTLE_ENDIAN

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

i = i++ nunca muda i

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

O tamanho das coleções e matrizes é sempre de 32 bits, independentemente de a JVM ser de 32 ou 64 bits.

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 bits, curto é 16 bits, int é 32 bits e longo é 64 bits.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.