Questa domanda è stato ispirato dalle (inattese) risultati di questo codice:c standard e bitshifts
uint16_t t16 = 0;
uint8_t t8 = 0x80;
uint8_t t8_res;
t16 = (t8 << 1);
t8_res = (t8 << 1);
printf("t16: %x\n", t16); // Expect 0, get 0x100
printf(" t8: %x\n", t8_res); // Expect 0, get 0
Ma si scopre questo ha un senso:
6.5.7 operatori di spostamento bit a bit
Vincoli
Ciascuno degli operandi, deve possedere intero tipo
Così la linea originariamente confusa equivale a:
t16 = (uint16_t) (((int) t8) << 1);
Un po IMHO non intuitivo, ma almeno ben definito.
Ok, grande, ma poi facciamo:
{
uint64_t t64 = 1;
t64 <<= 31;
printf("t64: %lx\n", t64); // Expect 0x80000000, get 0x80000000
t64 <<= 31;
printf("t64: %lx\n", t64); // Expect 0x0, get 0x4000000000000000
}
// edit: seguendo lo stesso argomento letterale come sopra, il seguente dovrebbe essere equivalente:
t64 = (uint64_t) (((int) t64) << 31);
// qui la mia confusione/expectation [end_edit]
Ora, otteniamo il risultato intuitivo, ma non quello che sarebbe derivato dalla mia lettura (letterale) dello standard. Quando/come si svolge questa "ulteriore promozione automatica del tipo"? O c'è una limitazione altrove che un tipo non può mai essere retrocesso (che avrebbe senso?), In questo caso, come si fa le regole di promozione valgono per:
uint32_t << uint64_t
Poiché la norma non dice entrambi gli argomenti sono promossi al int; entrambi gli argomenti dovrebbero essere promossi allo stesso tipo qui?
// edit:
Più specificamente, quale dovrebbe essere il risultato di:
uint32_t t32 = 1;
uint64_t t64_one = 1;
uint64_t t64_res;
t64_res = t32 << t64_one;
// fine modificare
La risposta alla domanda di cui sopra viene risolto quando ci rendiamo conto che le specifiche non richiede una promozione allo int
in particolare, piuttosto a uno integer type
, che uint64_t si qualifica come.
// PRECISAZIONE EDIT:
Ok, ma ora sono di nuovo confuso. In particolare, se uint8_t
è un tipo intero, perché viene promosso a int
? Non sembra essere correlato alla costante int 1, come il seguente esercizio dimostra:
{
uint16_t t16 = 0;
uint8_t t8 = 0x80;
uint8_t t8_one = 1;
uint8_t t8_res;
t16 = (t8 << t8_one);
t8_res = (t8 << t8_one);
printf("t16: %x\n", t16);
printf(" t8: %x\n", t8_res);
}
t16: 100
t8: 0
Perché il (T8 < < t8_one) espressione promosso se uint8_t è un tipo intero?
-
Per riferimento, sto lavorando da ISO/IEC 9899: TC9, WG14/N1124 6 maggio 2005. Se questo è fuori di data e qualcuno potrebbe anche fornire un collegamento a una copia più recente , anche questo sarebbe apprezzato.
non riesco bene a capire il motivo per cui si dice '// Si aspettano 0x0' dopo quel secondo turno data da 31 bit ... –
Sono confuso come Greg è, ma ci si aspetterebbe che i tipi non sono mai retrocessi automaticamente (si strinsero), solo promosso (ampliato). –
Dalla mia lettura dello standard, t64 = (uint64_t) (((int) t64) << 31) è una riga equivalente, nel qual caso il bit impostato dovrebbe essere perso per il troncamento int. – Pat