qual è la ragione per dichiarare esplicitamente L o UL per valori lunghi

Da un esempio

unsigned long x = 12345678UL 

Abbiamo sempre imparato che il compilatore deve vedere solo “long” nell’esempio sopra per impostare 4 byte (a 32 bit) di memoria. La domanda è: perché dovremmo usare L / UL in costanti lunghe anche dopo aver dichiarato che è lunga.

Quando non viene utilizzato un suffisso L o UL , il compilatore utilizza il primo tipo che può contenere la costante da un elenco (vedere i dettagli nello standard C99, clausola 6.4.4: 5. Per una costante decimale, l’elenco è int , long int long long int ).

Di conseguenza, la maggior parte delle volte, non è necessario utilizzare il suffisso. Non cambia il significato del programma. Non cambia il significato del tuo esempio di inizializzazione di x per la maggior parte delle architetture, anche se lo sarebbe se avessi scelto un numero che non poteva essere rappresentato come un long long . Vedi anche la risposta di codebauer per un esempio in cui è necessaria la parte U del suffisso.


Ci sono un paio di circostanze in cui il programmatore potrebbe voler impostare esplicitamente il tipo di costante. Un esempio è quando si utilizza una funzione variadica:

 printf("%lld", 1LL); // correct printf("%lld", 1); // undefined behavior 

Un motivo comune per utilizzare un suffisso è quello di garantire che il risultato di un calcolo non esca. Due esempi sono:

 long x = 10000L * 4096L; unsigned long long y = 1ULL << 36; 

In entrambi gli esempi, senza suffissi, le costanti avranno type int e il calcolo sarà effettuato come int . In ogni esempio questo comporta un rischio di overflow. L'uso dei suffissi significa che il calcolo sarà eseguito in un tipo più grande, che ha un intervallo sufficiente per il risultato.

Quando Lightness Races in Orbit lo mette, il suffisso del letterale viene prima dell'assegnazione. Nei due esempi sopra, semplicemente dichiarare x come long e y come unsigned long long non è sufficiente per impedire l'overflow nel calcolo delle espressioni assegnate a loro.


Un altro esempio è il confronto x < 12U dove la variabile x ha tipo int . Senza il suffisso U , il compilatore digita la costante 12 come un int , e il confronto è quindi un confronto tra i segni scritti.

 int x = -3; printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12 

Con il suffisso U , il confronto diventa un confronto tra interi non firmati. "Conversioni aritmetiche usuali" significa che -3 viene convertito in un grande int unsigned:

 printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large 

In effetti, il tipo di una costante può anche cambiare il risultato di un calcolo aritmetico, sempre a causa del modo in cui funzionano le "normali conversioni aritmetiche".


Si noti che, per le costanti decimali, l'elenco dei tipi suggeriti da C99 non contiene unsigned long long . In C90, l'elenco terminava con il più grande tipo di intero senza segno standardizzato al momento (che era unsigned long ). Una conseguenza è stata che il significato di alcuni programmi è stato modificato aggiungendo il tipo standard long long a C99: la stessa costante che è stata digitata come unsigned long in C90 ora potrebbe essere digitata come long long firmata piuttosto long long . Credo che questo sia il motivo per cui in C99, è stato deciso di non avere unsigned long long nella lista dei tipi per le costanti decimali. Vedi questo e questo blog post per un esempio.

Perché i valori letterali numerici sono tipici del tipo int. L’UL / L dice al compilatore che non sono di tipo int, ad esempio assumendo 32 bit int e 64 bit di lunghezza

 long i = 0xffff; long j = 0xffffUL; 

Qui i valori a destra devono essere convertiti in long firmati (32 bit -> 64 bit)

  1. Il “0xffff”, un int, verrebbe convertito in un’estensione di segno lunga usando, risultante in un valore negativo (0xffffffff)
  2. Il “0xffffUL”, un long senza segno, verrebbe convertito in long, risultando in un valore positivo (0x0000ffff)

La domanda è: perché dovremmo usare L / UL in costanti lunghe anche dopo aver dichiarato che è lunga.

Perché non è “dopo”; è “prima”.

Innanzitutto hai il letterale, quindi viene convertito in qualunque sia il tipo di variabile in cui stai cercando di comprimerlo.

Relativo a questo alberino è perché un u .

Un motivo per cui si deve consentire una costante intera maggiore di LLONG_MAX in forma decimale.

 // Likely to generate a warning. unsigned long long limit63bit = 18446744073709551615`; // 2^64 - 1 // OK unsigned long long limit63bit = 18446744073709551615u`;