2014-09-02 15 views
17

Sono perplesso da una differenza di comportamento tra MSVC e clang per questo codice:Come deve essere rappresentato un valore intero a 64 bit in C++?

#include <iostream> 
#include <cstdint> 

int main() { 
    int64_t wat = -2147483648; 
    std::cout << "0x" << std::hex << wat << std::endl; 

    return 0; 
} 

Visual Studio 2010, 2012, e il 2013 (su Windows 7) tutto schermo:

0x80000000 

Ma clang 503.0.40 (su OSX) display:

0xffffffff80000000 

Qual è il comportamento corretto secondo lo standard C++? Il letterale deve essere esteso a zero o esteso al segno a 64 bit?

Sono consapevole che lo int64_t wat = -2147483648LL; porterà allo stesso risultato su entrambi i compilatori, ma mi chiedo il comportamento corretto senza il suffisso letterale.

+1

Ho la sensazione che questo è cambiato in C++ 11 per dare il comportamento più sensibile si sta vedendo in precedenza con clang - Sono sicuro che un avvocato di lingua sarà presto per citare capitolo e versetto ... –

+0

@Paul R: Il comportamento "non sensibile" esisteva solo in C89/90, dove il compilatore doveva provare 'int',' long int' e 'unsigned long int' . L'inclusione del tipo unsigned è stata una decisione sbagliata, che è stata abbandonata in C099 e nella primissima versione di C++ (C++ 98). Ora il compilatore deve provare solo i tipi firmati, in ordine di larghezza crescente. In questo caso l'unica differenza di C++ 11 è l'aggiunta di "long long int". È puramente quantitativo. – AnT

+0

OK - grazie - forse mi stavo mescolando tra C e C++.FWIW Aggiungo sempre comunque il suffisso esplicito, quindi non devi mai pensare a quale dovrebbe essere il comportamento. –

risposta

13

Il tipo a sinistra dell'inizializzazione non ha importanza. L'espressione -2147483648 è interpretata da sola, indipendentemente.

letterale 2147483648 non ha suffissi, il che significa che il compilatore tenterà prima di interpretarlo come un valore int. Sulla tua piattaforma int è apparentemente un tipo a 32 bit. Il valore 2147483648 non rientra nell'intervallo del tipo intero a 32 bit con segno. Il compilatore deve utilizzare un numero intero con segno più ampio per rappresentare il valore, se disponibile (nella sequenza int, long int, long long int, con l'ultimo disponibile formalmente da C++ 11 in poi). Ma se nessun tipo intero sufficientemente ampia firmata è disponibile, il comportamento è indefinito

In MSVC storicamente long int ha la stessa larghezza int, anche se a 64 bit long long int è supportata anche in versioni successive di MSVC. Tuttavia, anche in VS2013 (che supporta long long int) ottengo

warning C4146: unary minus operator applied to unsigned type, result still unsigned 

in risposta alla vostra inizializzazione. Ciò significa che MSVC si attacca ancora alle regole arcaiche C89/90 dell'interpretazione letterale dell'intero (dove i tipi sono stati scelti dalla sequenza int, long int, unsigned long int).

Si noti che MSVC non è ufficialmente un compilatore C++ 11. Quindi formalmente non deve provare long long int. Tale tipo non esiste formalmente nel linguaggio pre-C++ 11. Da questo punto di vista, MSVC non ha un numero intero con segno sufficientemente grande da utilizzare in questo caso e il comportamento non è definito. All'interno della libertà offerta da un comportamento indefinito, l'uso delle regole C89/90 per un'interpretazione letterale intera è perfettamente giustificabile.

Si potrebbe anche dare un'occhiata a questo (-2147483648> 0) returns true in C++?

+0

Penso che dipenda dal fatto che tu stia compilando come C++ 11 o no? –

+0

@Paul R: Come? Poiché i letterali integer "suffixless" C++ 98 dovevano essere provati per 'int' e' long int'. In MSVC entrambi hanno normalmente la stessa larghezza. – AnT

+0

La riga di comando che sto utilizzando per MSVC è 'cl wat.cpp/EHsc', quindi nessun flag speciale diverso da quello per la gestione delle eccezioni. Non penso che ci sia un flag C++ 11 in MSVC. –

Problemi correlati