Domanda

Dato il seguente frammento di codice:

#include <stdio.h>

typedef signed long long int64;
typedef signed int int32;
typedef signed char int8;

int main()
{
    printf("%i\n", sizeof(int8));
    printf("%i\n", sizeof(int32));
    printf("%i\n", sizeof(int64));

    int8 a = 100;
    int8 b = 100;
    int32 c = a * b;
    printf("%i\n", c);

    int32 d = 1000000000;
    int32 e = 1000000000;
    int64 f = d * e;
    printf("%I64d\n", f);
}

L'uscita con MinGW GCC 3.4.5 è (-O0):

1
4
8
10000
-1486618624

La prima moltiplicazione viene colato un int32 internamente (secondo l'uscita assemblatore). La seconda moltiplicazione non viene colato. Non sono sicuro se i risultati differiscono in quanto il programma è stato eseguito su un IA32, o perché è definita da qualche parte nello standard C. Tuttavia mi interessa se questo comportamento esatto è definito da qualche parte (ISO / IEC 9899?), Perché mi piace capire meglio perché e quando ho lanciare manualmente (ho problemi di porting di un programma da una diversa architettura).

È stato utile?

Soluzione

Lo standard C99 fa specificare che gli operatori binari come * non operare su tipi interi più piccoli di int. Espressioni di questo tipo sono promossi al int prima di applicare l'operatore. Vedere 6.3.1.4 paragrafo 2 e le numerose occorrenze delle parole "integer promozione". Ma questo è un po ortogonale alle istruzioni di montaggio generate dal compilatore, che operano su ints perché questo è più veloce anche quando il compilatore sarebbe consentito di calcolato un risultato più corto (perché il risultato viene immediatamente memorizzato in un l-value di un tipo corto , per esempio).

Per quanto riguarda int64 f = d * e; dove d e e sono di tipo int, la moltiplicazione è fatto come un int secondo le stesse regole di promozione. L'overflow è tecnicamente comportamento non definito , si stanno ottenendo risultati di due-s-complemento qui, ma si potrebbe ottenere qualche cosa secondo la norma.

Nota: le regole di promozione distinguono la firmati e non firmati tipi quando la promozione. La regola è promuovere tipi piccole per int meno int non può rappresentare tutti i valori del tipo, in cui viene utilizzato caso unsigned int.

Altri suggerimenti

Il problema è che la moltiplicazione è int32 int32 *, che avviene come int32, e il risultato poi assegnato a un Int64. Si otterrebbe lo stesso effetto con double d = 3 / 2;, che dividerebbe 3 da 2 utilizzando divisione intera, e assegnare 1,0 a d.

Si deve prestare attenzione al tipo di un'espressione o sottoespressione ogni volta che può questione. Ciò richiede assicurandosi che l'operazione appropriata è calcolato come il tipo appropriato, come lanciare una delle multiplicands a Int64, o (nel mio esempio) o 3.0 / 2 (float)3 / 2.

Leggi K & R (l'originale). Tutte le operazioni di interi vengono effettuate con il tipo intero naturale a meno che non si tratta di variabili che sono (o sono fuso) a qualcosa di più grande. Le operazioni di char casted a 32 bit perché è la dimensione naturale intero su tale architettura. La moltiplicazione dei due numeri interi a 32 bit è fatto in 32 bit, perché nulla è colata a qualcosa di più grande (fino a quando si assegna alla variabile a 64 bit, ma questo è troppo tardi). Se si desidera che l'operazione avvenga a 64 bit, lanciare uno o entrambi gli interi a 64 bit.

int64 f = (int64)d * e;

a * b è calcolato come un int, e poi gettato al tipo di variabile di ricezione (che avviene solo per essere int)

d * e è calcolato come un int, e poi gettato al tipo di variabile di ricezione (che avviene solo per essere Int64)

Se una delle variabili di tipo erano più grandi che un int (o erano virgola mobile), di questo tipo sarebbe stato utilizzato. Ma dal momento che tutti i tipi utilizzati nelle moltiplica erano int o più piccolo, sono stati utilizzati int.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top