Ricerca…


Stampa del valore di un puntatore su un oggetto

Per stampare il valore di un puntatore su un oggetto (al contrario di un puntatore di funzione), utilizzare lo specificatore di conversione p . È stato definito per stampare solo i segnapunti void , quindi per stampare il valore di un punto non void deve essere convertito in modo esplicito ("castato *") per void* .

#include <stdlib.h> /* for EXIT_SUCCESS */
#include <stdio.h>  /* for printf() */

int main(void)
{
  int i;
  int * p = &i;

  printf("The address of i is %p.\n", (void*) p);

  return EXIT_SUCCESS;
}
C99

Usando <inttypes.h> e uintptr_t

Un altro modo per stampare i puntatori in C99 o uintptr_t successive utilizza il tipo uintptr_t e le macro da <inttypes.h> :

#include <inttypes.h> /* for uintptr_t and PRIXPTR */
#include <stdio.h>    /* for printf() */

int main(void)
{
  int  i;
  int *p = &i;

  printf("The address of i is 0x%" PRIXPTR ".\n", (uintptr_t)p);

  return 0;
}

In teoria, potrebbe non esserci un tipo intero che può contenere qualsiasi puntatore convertito in un numero intero (quindi il tipo uintptr_t potrebbe non esistere). In pratica, esiste. I puntatori alle funzioni non devono essere convertibili nel tipo uintptr_t , anche se spesso sono più convertibili.

Se il tipo uintptr_t esiste, lo stesso intptr_t tipo intptr_t . Non è chiaro il motivo per cui si vorrebbe mai trattare gli indirizzi come interi con segno, però.

K & R C89

Storia pre-standard:

Prima di C89 durante i tempi di K & R-C non c'era nessun tipo void* (né header <stdlib.h> , né prototipi, e quindi nessuna notazione int main(void) ), quindi il puntatore è stato castato su long unsigned int e stampato usando il modificatore di lunghezza / identificatore di conversione lx .

L'esempio sotto è solo a scopo informativo. Oggigiorno questo è un codice non valido, che molto bene potrebbe provocare il famigerato comportamento indefinito .

#include <stdio.h> /* optional in pre-standard C - for printf() */

int main()
{
  int  i;
  int *p = &i;

  printf("The address of i is 0x%lx.\n", (long unsigned) p);

  return 0;
}

Stampa della differenza dei valori di due puntatori su un oggetto

Sottraendo i valori di due puntatori a un oggetto si ottiene un numero intero con segno * 1 . Quindi verrebbe stampato utilizzando almeno lo specifier di conversione d .

Per assicurarsi che ci sia un tipo abbastanza largo da contenere una "differenza puntatore", dato che C99 <stddef.h> definisce il tipo ptrdiff_t . Per stampare un ptrdiff_t usa il modificatore di lunghezza t .

C99
#include <stdlib.h> /* for EXIT_SUCCESS */
#include <stdio.h> /* for printf() */
#include <stddef.h> /* for ptrdiff_t */


int main(void)
{
  int a[2];
  int * p1 = &a[0], * p2 = &a[1];
  ptrdiff_t pd = p2 - p1;

  printf("p1 = %p\n", (void*) p1);
  printf("p2 = %p\n", (void*) p2);
  printf("p2 - p1 = %td\n", pd);

  return EXIT_SUCCESS;
}

Il risultato potrebbe essere simile a questo:

p1 = 0x7fff6679f430
p2 = 0x7fff6679f434
p2 - p1 = 1

Si noti che il valore risultante della differenza viene ridimensionato in base alla dimensione del puntatore sottratto dal puntatore, un int qui. La dimensione di un int per questo esempio è 4.


* 1 Se i due puntatori da sottrarre non puntano allo stesso oggetto, il comportamento non è definito.

Specifiers di conversione per la stampa

Identificatore di conversione Tipo di argomento Descrizione
i , d int stampa decimale
u int non firmato stampa decimale
o int non firmato stampa ottale
x int non firmato stampa esadecimale, minuscolo
X int non firmato stampa esadecimale, maiuscolo
f Doppio stampa fluttuante con una precisione predefinita di 6, se non viene fornita alcuna precisione (minuscole utilizzate per numeri speciali nan e inf o infinity )
F Doppio stampa fluttuante con una precisione predefinita di 6, se non viene fornita alcuna precisione (maiuscole utilizzate per numeri speciali NAN e INF o INFINITY )
e Doppio le stampe fluttuano con una precisione predefinita di 6, se non viene data alcuna precisione, usando la notazione scientifica usando mantissa / esponente; esponente minuscolo e numeri speciali
E Doppio le stampe fluttuano con una precisione predefinita di 6, se non viene data alcuna precisione, usando la notazione scientifica usando mantissa / esponente; esponente maiuscolo e numeri speciali
g Doppio utilizza o f o e [vedi sotto]
G Doppio usa F o E [vedi sotto]
a Doppio stampa esadecimale, minuscolo
A Doppio stampa esadecimale, maiuscolo
c carbonizzare stampa carattere singolo
s char * stampa una stringa di caratteri fino a un terminatore NUL o troncato a lunghezza data dalla precisione, se specificato
p void * stampa void -pointer value; un void non void dovrebbe essere convertito esplicitamente ("cast") a void* ; puntatore all'oggetto solo, non a un puntatore di funzione
% n / A stampa il carattere %
n int * scrivere il numero di byte stampati finora nel int indicò.

Si noti che i modificatori di lunghezza possono essere applicati a %n (ad esempio %hhn indica che un %hhn conversione n successivo si applica a un puntatore a un argomento signed char , in base alla ISO / IEC 9899: 2011 §7.21.6.1 ¶7).

Si noti che le conversioni in virgola mobile si applicano ai tipi float e double causa delle regole di promozione predefinite - §6.5.2.2 Chiamate di funzione, ¶ 7 La notazione dei puntini di sospensione in un dichiaratore di prototipo di funzione causa l'interruzione della conversione del tipo di argomento dopo l'ultimo parametro dichiarato. Le promozioni degli argomenti predefiniti vengono eseguite sugli argomenti finali. Quindi, funzioni come printf() sono sempre passate solo double valori, anche se la variabile di riferimento è di tipo float .

Con i formati g e G , la scelta tra la notazione e ed f (o E e F ) è documentata nello standard C e nelle specifiche POSIX per printf() :

Il doppio argomento che rappresenta un numero in virgola mobile deve essere convertito nello stile f o e (o nello stile F o E nel caso di un G conversione G ), a seconda del valore convertito e della precisione. Sia P la precisione se non zero, 6 se la precisione è omessa, o 1 se la precisione è zero. Quindi, se una conversione con lo stile E avrebbe un esponente di X :

  • Se P> X> = -4, la conversione deve essere con lo stile f (o F ) e con precisione P - (X+1) .
  • Altrimenti, la conversione deve essere con stile e (o E ) e precisione P - 1 .

Infine, a meno che non sia usato il contrassegno "#", tutti gli zeri finali devono essere rimossi dalla parte frazionaria del risultato e il carattere del punto decimale deve essere rimosso se non è rimasta alcuna parte frazionaria.

La funzione printf ()

Acceduto tramite l'inclusione di <stdio.h> , la funzione printf() è lo strumento principale utilizzato per stampare il testo sulla console in C.

printf("Hello world!");
// Hello world!

Gli array di caratteri normali e non formattati possono essere stampati da soli posizionandoli direttamente tra le parentesi.

printf("%d is the answer to life, the universe, and everything.", 42);
// 42 is the answer to life, the universe, and everything.

int x = 3;
char y = 'Z';
char* z = "Example";
printf("Int: %d, Char: %c, String: %s", x, y, z);
// Int: 3, Char: Z, String: Example

In alternativa, è possibile stampare numeri interi, numeri in virgola mobile, caratteri e altro utilizzando il carattere di escape % , seguito da un carattere o sequenza di caratteri che denotano il formato, noto come specificatore di formato .

Tutti gli argomenti aggiuntivi alla funzione printf() sono separati da virgole e questi argomenti dovrebbero essere nello stesso ordine degli specificatori di formato. Argomenti aggiuntivi vengono ignorati, mentre gli argomenti digitati in modo errato o la mancanza di argomenti causano errori o comportamenti non definiti. Ogni argomento può essere un valore letterale o una variabile.

Al termine dell'esecuzione, il numero di caratteri stampati viene restituito con tipo int . In caso contrario, un errore restituisce un valore negativo.

Modificatori di lunghezza

Gli standard C99 e C11 specificano i seguenti modificatori di lunghezza per printf() ; i loro significati sono:

Modificatore Modifica Si applica a
hh d, i, o, u, x o X char , char signed char o unsigned char
h d, i, o, u, x o X short int o unsigned short int
l d, i, o, u, x o X long int o unsigned long int
l a, A, e, E, f, F, g o G double (per compatibilità con scanf() ; indefinito in C90)
ll d, i, o, u, x o X long long int o unsigned long long int
j d, i, o, u, x o X intmax_t o uintmax_t
z d, i, o, u, x o X size_t o il tipo firmato corrispondente ( ssize_t in POSIX)
t d, i, o, u, x o X ptrdiff_t o il corrispondente numero intero senza segno
L a, A, e, E, f, F, g o G long double

Se un modificatore di lunghezza viene visualizzato con un identificatore di conversione diverso da quello specificato sopra, il comportamento non è definito.

Microsoft specifica alcuni modificatori di lunghezza diversi e in modo esplicito non supporta hh , j , z o t .

Modificatore Modifica Si applica a
I32 d, i, o, x o X __int32
I32 o, u, x o X unsigned __int32
I64 d, i, o, x o X __int64
I64 o, u, x o X unsigned __int64
io d, i, o, x o X ptrdiff_t (cioè __int32 su __int32 a 32 bit, __int64 su piattaforme a 64 bit)
io o, u, x o X size_t (ovvero, unsigned __int32 su unsigned __int32 a 32 bit, unsigned __int64 su piattaforme a 64 bit)
io L a, A, e, E, f, g o G long double (In Visual C ++, anche se long double è un tipo distinto, ha la stessa rappresentazione interna del double ).
io w c o C Ampio personaggio con funzioni printf e wprintf . (Un wC tipo lc , lC , wc o wC è sinonimo di C nelle funzioni printf e con c nelle funzioni wprintf .)
io w s, S o Z Stringa di caratteri wprintf funzioni printf e wprintf . (Un wS tipo ls , lS , ws o wS è sinonimo di S nelle funzioni printf e con s nelle funzioni wprintf .)

Notare che gli Z conversione C , S e Z ei modificatori di lunghezza I , I32 , I64 e w sono estensioni Microsoft. Trattare l come modificatore per il long double anziché il double è diverso dallo standard, anche se sarà difficile individuare la differenza a meno che il long double non abbia una rappresentazione diversa dal double .

Flag di formato di stampa

Lo standard C (C11 e C99) definisce i seguenti flag per printf() :

Bandiera conversioni Senso
- tutti Il risultato della conversione deve essere giustificato a sinistra all'interno del campo. La conversione è giustificata a destra se questo flag non è specificato.
+ numerico firmato Il risultato di una conversione firmata inizia sempre con un segno ('+' o '-' '). La conversione inizia con un segno solo quando un valore negativo viene convertito se questo flag non è specificato.
<space> numerico firmato Se il primo carattere di una conversione firmata non è un segno o se una conversione firmata non produce alcun carattere, uno <space> deve essere preceduto dal risultato. Ciò significa che se appaiono entrambi i flag <space> e " + ", il flag <space> deve essere ignorato.
# tutti Specifica che il valore deve essere convertito in un modulo alternativo. Per o conversione, essa aumenta la precisione, se e solo se necessario, di forzare la prima cifra del risultato da uno zero (se il valore e la precisione sono entrambi 0, un singolo 0 è stampato). Per gli specificatori di conversione x o X , un risultato diverso da zero deve avere 0x (o 0X ) come prefisso. Per gli specificatori di conversione a , A , e , E , f , F , g e G , il risultato deve sempre contenere un carattere di radice, anche se nessuna cifra segue il carattere di radice. Senza questo flag, un carattere di radice appare nel risultato di queste conversioni solo se una cifra lo segue. Per gli specificatori di conversione g e G , gli zeri finali non devono essere rimossi dal risultato come normalmente. Per altri specificatori di conversione, il comportamento non è definito.
0 numerico Per gli identificatori di conversione d, i, o, u, x, X, a, A, e, E, f, G e G, gli zeri iniziali (a seguito di qualsiasi indicazione di segno o base) vengono utilizzati per eseguire il rilievo sul campo larghezza invece di eseguire il riempimento dello spazio, tranne quando si converte un infinito o NaN. Se appaiono entrambi i flag "0" e "-", il flag "0" viene ignorato. Per gli identificatori di conversione d, i, o, u, xe X, se viene specificata una precisione, il flag '0' deve essere ignorato. ⌦ Se appaiono entrambi i flag "0" e <apostrophe> , i caratteri di raggruppamento vengono inseriti prima dello zero padding. Per le altre conversioni, il comportamento non è definito. ⌫

Questi flag sono supportati anche da Microsoft con lo stesso significato.

La specifica POSIX per printf() aggiunge:

Bandiera conversioni Senso
' i, d, u, f, F, g, G La parte intera del risultato di una conversione decimale deve essere formattata con migliaia di caratteri di raggruppamento. Per altre conversioni il comportamento non è definito. Viene utilizzato il carattere di raggruppamento non monetario.


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow