C Language
Tipi di dati
Ricerca…
Osservazioni
- Mentre
char
è richiesto per essere 1 byte, 1 byte non è richiesto per essere 8 bit (spesso chiamato anche un ottetto ), anche se la maggior parte delle moderne piattaforme di computer lo definiscono come 8 bit. Il numero di bit di implementazione perchar
è fornito dalla macroCHAR_BIT
, definita in<limits.h>
. POSIX richiede 1 byte per essere 8 bit. - I tipi di interi a larghezza fissa dovrebbero essere usati scarsamente, i tipi di C incorporati sono progettati per essere naturali su ogni architettura, i tipi a larghezza fissa dovrebbero essere usati solo se avete bisogno esplicitamente di un numero intero specifico (ad esempio per il networking).
Tipi interi e costanti
Gli interi firmati possono essere di questi tipi (l' int
dopo l' short
o l'opzione long
è facoltativo):
signed char c = 127; /* required to be 1 byte, see remarks for further information. */
signed short int si = 32767; /* required to be at least 16 bits. */
signed int i = 32767; /* required to be at least 16 bits */
signed long int li = 2147483647; /* required to be at least 32 bits. */
signed long long int li = 2147483647; /* required to be at least 64 bits */
Ognuno di questi tipi di interi con segno ha una versione senza firma.
unsigned int i = 65535;
unsigned short = 2767;
unsigned char = 255;
Per tutti i tipi, ma char
la signed
versione si presume se il signed
o unsigned
parte viene omesso. Il tipo char
costituisce un terzo tipo di carattere, diverso dal signed char
e dal signed char
unsigned char
e la signness (o meno) dipende dalla piattaforma.
Diversi tipi di costanti intere (chiamate letterali in C jargon) possono essere scritti in basi diverse e larghezza diversa, in base al loro prefisso o suffisso.
/* the following variables are initialized to the same value: */
int d = 42; /* decimal constant (base10) */
int o = 052; /* octal constant (base8) */
int x = 0xaf; /* hexadecimal constants (base16) */
int X = 0XAf; /* (letters 'a' through 'f' (case insensitive) represent 10 through 15) */
Le costanti decimali sono sempre signed
. Le costanti esadecimali iniziano con 0x
o 0X
e le costanti ottali iniziano solo con uno 0
. Gli ultimi due sono signed
o unsigned
seconda che il valore si adatti al tipo firmato o meno.
/* suffixes to describe width and signedness : */
long int i = 0x32; /* no suffix represent int, or long int */
unsigned int ui = 65535u; /* u or U represent unsigned int, or long int */
long int li = 65536l; /* l or L represent long int */
Senza un suffisso la costante ha il primo tipo che si adatta al suo valore, cioè una costante decimale che è maggiore di INT_MAX
è di tipo long
se possibile, o long long
altrimenti.
Il file di intestazione <limits.h>
descrive i limiti degli interi come segue. I loro valori definiti dall'implementazione devono essere uguali o maggiori in grandezza (valore assoluto) a quelli mostrati sotto, con lo stesso segno.
macro | genere | Valore |
---|---|---|
CHAR_BIT | l'oggetto più piccolo che non è un bit-field (byte) | 8 |
SCHAR_MIN | signed char | -127 / - (2 7 - 1) |
SCHAR_MAX | signed char | +127 / 2 7 - 1 |
UCHAR_MAX | unsigned char | 255/2 8 - 1 |
CHAR_MIN | char | vedi sotto |
CHAR_MAX | char | vedi sotto |
SHRT_MIN | short int | -32767 / - (2 15 - 1) |
SHRT_MAX | short int | +32767 / 2 15 - 1 |
USHRT_MAX | unsigned short int | 65535/2 16 - 1 |
INT_MIN | int | -32767 / - (2 15 - 1) |
INT_MAX | int | +32767 / 2 15 - 1 |
UINT_MAX | unsigned int | 65535/2 16 - 1 |
LONG_MIN | long int | -2147483647 / - (2 31 - 1) |
LONG_MAX | long int | +2147483647 / 2 31 - 1 |
ULONG_MAX | unsigned long int | 4294967295/2 32 - 1 |
macro | genere | Valore |
---|---|---|
LLONG_MIN | long long int | -9223372036854775807 / - (2 63 - 1) |
LLONG_MAX | long long int | +9223372036854775807 / 2 63 - 1 |
ULLONG_MAX | unsigned long long int | 18446744073709551615/2 64 - 1 |
Se il valore di un oggetto di tipo char
sign-extends quando utilizzato in un'espressione, il valore di CHAR_MIN
deve essere uguale a quello di SCHAR_MIN
e il valore di CHAR_MAX
deve essere uguale a quello di SCHAR_MAX
. Se il valore di un oggetto di tipo char
non si estende al segno quando utilizzato in un'espressione, il valore di CHAR_MIN
deve essere 0 e il valore di CHAR_MAX
deve essere uguale a quello di UCHAR_MAX
.
Lo standard C99 ha aggiunto una nuova intestazione, <stdint.h>
, che contiene definizioni per numeri interi a larghezza fissa. Vedere l'esempio intero a larghezza fissa per una spiegazione più approfondita.
String letterali
Una stringa letterale in C è una sequenza di caratteri, terminata da uno zero letterale.
char* str = "hello, world"; /* string literal */
/* string literals can be used to initialize arrays */
char a1[] = "abc"; /* a1 is char[4] holding {'a','b','c','\0'} */
char a2[4] = "abc"; /* same as a1 */
char a3[3] = "abc"; /* a1 is char[3] holding {'a','b','c'}, missing the '\0' */
I valori letterali delle stringhe non sono modificabili (e infatti possono essere inseriti nella memoria di sola lettura come .rodata). Il tentativo di modificare i loro valori comporta un comportamento indefinito.
char* s = "foobar";
s[0] = 'F'; /* undefined behaviour */
/* it's good practice to denote string literals as such, by using `const` */
char const* s1 = "foobar";
s1[0] = 'F'; /* compiler error! */
I letterali a più stringhe sono concatenati in fase di compilazione, il che significa che puoi scrivere un costrutto come questi.
/* only two narrow or two wide string literals may be concatenated */
char* s = "Hello, " "World";
/* since C99, more than two can be concatenated */
/* concatenation is implementation defined */
char* s1 = "Hello" ", " "World";
/* common usages are concatenations of format strings */
char* fmt = "%" PRId16; /* PRId16 macro since C99 */
I valori letterali stringa, come le costanti dei caratteri, supportano set di caratteri diversi.
/* normal string literal, of type char[] */
char* s1 = "abc";
/* wide character string literal, of type wchar_t[] */
wchar_t* s2 = L"abc";
/* UTF-8 string literal, of type char[] */
char* s3 = u8"abc";
/* 16-bit wide string literal, of type char16_t[] */
char16_t* s4 = u"abc";
/* 32-bit wide string literal, of type char32_t[] */
char32_t* s5 = U"abc";
Tipi interi a larghezza fissa (dal C99)
L'intestazione <stdint.h>
fornisce diverse definizioni di tipi interi a larghezza fissa. Questi tipi sono facoltativi e vengono forniti solo se la piattaforma ha un tipo intero della larghezza corrispondente e se il corrispondente tipo firmato ha una rappresentazione a complemento a due di valori negativi.
Vedere la sezione commenti per suggerimenti sull'utilizzo di tipi di larghezza fissa.
/* commonly used types include */
uint32_t u32 = 32; /* exactly 32-bits wide */
uint8_t u8 = 255; /* exactly 8-bits wide */
int64_t i64 = -65 /* exactly 64 bit in two's complement representation */
Costanti a virgola mobile
Il linguaggio C ha tre tipi di virgola mobile reali obbligatori, float
, double
e long double
.
float f = 0.314f; /* suffix f or F denotes type float */
double d = 0.314; /* no suffix denotes double */
long double ld = 0.314l; /* suffix l or L denotes long double */
/* the different parts of a floating point definition are optional */
double x = 1.; /* valid, fractional part is optional */
double y = .1; /* valid, whole-number part is optional */
/* they can also defined in scientific notation */
double sd = 1.2e3; /* decimal fraction 1.2 is scaled by 10^3, that is 1200.0 */
L'intestazione <float.h>
definisce vari limiti per le operazioni in virgola mobile.
L'aritmetica in virgola mobile è definita dall'implementazione. Tuttavia, la maggior parte delle piattaforme moderne (arm, x86, x86_64, MIPS) utilizzano operazioni in virgola mobile IEEE 754 .
C ha anche tre tipi di floating point complessi opzionali derivati da quanto sopra.
Interpretazione delle dichiarazioni
Una peculiarità sintattica distintiva di C è che le dichiarazioni rispecchiano l'uso dell'oggetto dichiarato come sarebbe in un'espressione normale.
Il seguente insieme di operatori con identica precedenza e associatività viene riutilizzato nei dichiaratori, vale a dire:
- l'operatore unario
*
"dereferenziazione" che denota un puntatore; - l'operatore binario
[]
"subscription in array" che denota una matrice; - l'operatore (1 + n) -ary
()
"chiamata di funzione" che denota una funzione; - il
()
raggruppa le parentesi che sovrascrivono la precedenza e l'associatività del resto degli operatori elencati.
I tre operatori precedenti hanno la seguente precedenza e associatività:
Operatore | Precedenza relativa | Associatività |
---|---|---|
[] (abbonamento array) | 1 | Da sinistra a destra |
() (chiamata di funzione) | 1 | Da sinistra a destra |
* (dereferenziazione) | 2 | Da destra a sinistra |
Quando si interpretano le dichiarazioni, si deve partire dall'identificatore verso l'esterno e applicare gli operatori adiacenti nell'ordine corretto come nella tabella precedente. Ogni applicazione di un operatore può essere sostituita con le seguenti parole inglesi:
Espressione | Interpretazione |
---|---|
thing[X] | una serie di dimensioni X di ... |
thing(t1, t2, t3) | una funzione che prende t1 , t2 , t3 e restituisce ... |
*thing | un puntatore a ... |
Ne consegue che l'inizio dell'interpretazione inglese inizierà sempre con l'identificatore e terminerà con il tipo che si trova sul lato sinistro della dichiarazione.
Esempi
char *names[20];
[]
ha la precedenza su *
, quindi l'interpretazione è: i names
sono una matrice di dimensione 20 di un puntatore a char
.
char (*place)[10];
Nel caso in cui si utilizzino le parentesi per sovrascrivere la precedenza, viene applicato prima *
: place
è un puntatore a una matrice di dimensione 10 di char
.
int fn(long, short);
Non c'è alcuna precedenza da preoccupare qui: fn
è una funzione che richiede long
, short
e ritorno int
.
int *fn(void);
Il fn
()
viene applicato per primo: fn
è una funzione che prende il void
e restituisce un puntatore a int
.
int (*fp)(void);
Sovrascrivere la precedenza di ()
: fp
è un puntatore a una funzione che prende il void
e che restituisce int
.
int arr[5][8];
Gli array multidimensionali non sono un'eccezione alla regola; gli operatori []
sono applicati nell'ordine da sinistra a destra secondo l'associatività nella tabella: arr
è una matrice di dimensione 5 di una matrice di dimensione 8 di int
.
int **ptr;
I due operatori di dereferenziazione hanno la stessa precedenza, quindi l'associatività ha effetto. Gli operatori sono applicati nell'ordine da destra a sinistra: ptr
è un puntatore a un puntatore a un int
.
Dichiarazioni multiple
La virgola può essere utilizzata come separatore (* non * che agisce come l'operatore virgola) per delimitare più dichiarazioni all'interno di una singola istruzione. La seguente dichiarazione contiene cinque dichiarazioni:int fn(void), *ptr, (*fp)(int), arr[10][20], num;
Gli oggetti dichiarati nell'esempio precedente sono:
-
fn
: una funzione che sivoid
e restituisceint
; -
ptr
: un puntatore a unint
; -
fp
: un puntatore a una funzione che assumeint
e restituisceint
; -
arr
: una matrice di dimensione 10 di una matrice di dimensione 20 diint
; -
num
:int
.
Interpretazione alternativa
Poiché il mirror delle dichiarazioni viene utilizzato, una dichiarazione può anche essere interpretata in termini di operatori che potrebbero essere applicati sull'oggetto e il tipo risultante finale di tale espressione. Il tipo che si trova sul lato sinistro è il risultato finale che viene restituito dopo l'applicazione di tutti gli operatori.
/*
* Subscripting "arr" and dereferencing it yields a "char" result.
* Particularly: *arr[5] is of type "char".
*/
char *arr[20];
/*
* Calling "fn" yields an "int" result.
* Particularly: fn('b') is of type "int".
*/
int fn(char);
/*
* Dereferencing "fp" and then calling it yields an "int" result.
* Particularly: (*fp)() is of type "int".
*/
int (*fp)(void);
/*
* Subscripting "strings" twice and dereferencing it yields a "char" result.
* Particularly: *strings[5][15] is of type "char"
*/
char *strings[10][20];