C Language
Форматированный вход / выход
Поиск…
Печать значения указателя на объект
Чтобы напечатать значение указателя на объект (в отличие от указателя функции), используйте спецификатор преобразования p
. Он определяется только для печати void
-pointers, поэтому для распечатки значения не- void
-pointer он должен быть явно преобразован («casted *») в 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;
}
Использование <inttypes.h>
и uintptr_t
Другой способ печати указателей на C99 или более поздней версии использует тип uintptr_t
и макросы из <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;
}
Теоретически не может быть целочисленного типа, который может содержать любой указатель, преобразованный в целое число (поэтому тип uintptr_t
может не существовать). На практике это действительно существует. Указатели на функции не должны быть конвертируемыми в тип uintptr_t
хотя они чаще всего являются конвертируемыми.
Если тип uintptr_t
существует, то intptr_t
тип intptr_t
. Непонятно, почему вы когда-либо хотели обрабатывать адреса как целые числа.
Предварительная стандартная история:
До C89 во время K & R-C не было никакого типа void*
(ни заголовок <stdlib.h>
, ни прототипы, и, следовательно, нет int main(void)
notation), поэтому указатель был отброшен до long unsigned int
и напечатан с использованием модификатор длины lx
/ спецификатор преобразования.
Пример, приведенный ниже, предназначен только для информационных целей. В настоящее время это неверный код, который очень хорошо может спровоцировать печально известное Undefined Behavior .
#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;
}
Печать разницы значений двух указателей на объект
Вычитание значений двух указателей на объект приводит к значению целого числа * 1 . Таким образом, он будет напечатан с использованием, по крайней мере, спецификатора преобразования d
.
Чтобы убедиться, что существует такой тип, достаточно широкий, чтобы провести такую «разницу между указателями», так как C99 <stddef.h>
определяет тип ptrdiff_t
. Чтобы напечатать ptrdiff_t
используйте модификатор t
длины.
#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;
}
Результат может выглядеть так:
p1 = 0x7fff6679f430
p2 = 0x7fff6679f434
p2 - p1 = 1
Обратите внимание, что результирующее значение разности масштабируется по размеру типа, на который указывает вычитаемая точка, int
здесь. Размер int
для этого примера равен 4.
* 1 Если два указателя, которые нужно вычесть, не указывают на один и тот же объект, поведение не определено.
Спецификации преобразования для печати
Спецификация конверсии | Тип аргумента | Описание |
---|---|---|
i , d | ИНТ | печатает десятичные числа |
u | unsigned int | печатает десятичные числа |
o | unsigned int | отпечатки восьмеричные |
x | unsigned int | печатает шестнадцатеричный, строчный |
X | unsigned int | печатает шестнадцатеричный, верхний регистр |
f | двойной | печатает float с точностью по умолчанию 6, если не задана точность (нижний регистр используется для специальных чисел nan и inf или infinity ) |
F | двойной | prints float с точностью по умолчанию 6, если точность не задана (верхний регистр используется для специальных номеров NAN и INF или INFINITY ) |
e | двойной | печатает float с точностью по умолчанию 6, если точность не задана, используя научную нотацию с использованием мантиссы / экспоненты; индекс нижнего регистра и специальные номера |
E | двойной | печатает float с точностью по умолчанию 6, если точность не задана, используя научную нотацию с использованием мантиссы / экспоненты; индекс верхнего регистра и специальные числа |
g | двойной | использует либо f либо e [см. ниже] |
G | двойной | использует F или E [см. ниже] |
a | двойной | печатает шестнадцатеричный, строчный |
A | двойной | печатает шестнадцатеричный, верхний регистр |
c | голец | печатает один символ |
s | символ * | печатает строку символов до терминатора NUL или усекает до длины, заданной точностью, если указано |
p | недействительным * | печатает значение void -pointer; не void -указатель должен быть явно преобразован ( «слепок») к void* ; указатель на объект, а не указатель функции |
% | н / | печатает символ % |
n | int * | напишите количество байт, напечатанных до сих пор в int указывает. |
Обратите внимание, что модификаторы длины могут быть применены к %n
(например, %hhn
указывает, что следующий указатель преобразования n
применяется к указателю на знак signed char
соответствии с ISO / IEC 9899: 2011 §7.21.6.1 ¶7).
Обратите внимание, что преобразования с плавающей запятой применяются к типам float
и double
из-за правил рассылки по умолчанию - §6.5.2.2. Вызовы функций, ¶7 . Обозначение многоточия в деклараторе прототипа функции приводит к тому, что преобразование типа аргумента останавливается после последнего объявленного параметра. Продвижение аргументов по умолчанию выполняется по завершающим аргументам. ) Таким образом, такие функции, как printf()
передаются только double
, даже если указанная переменная имеет тип float
.
В форматах g
и G
выбор между обозначениями e
и f
(или E
и F
) документируется в стандарте C и в спецификации POSIX для printf()
:
Двойной аргумент, представляющий число с плавающей запятой, должен быть преобразован в стиле
f
илиe
(или в стилеF
илиE
в случае спецификатора преобразованияG
), в зависимости от преобразованного значения и точности. ПустьP
равно точности, если отличная от нуля, 6, если точность опущена, или 1, если точность равна нулю. Тогда, если преобразование со стилемE
будет иметь показательX
:
- Если P> X> = -4, преобразование должно быть со стилем
f
(илиF
) и точностьюP - (X+1)
.- В противном случае преобразование должно быть со стилем
e
(илиE
) и точностьюP - 1
.
Наконец, если не используется флаг «#», любые конечные нули должны быть удалены из дробной части результата, а символ десятичной точки должен быть удален, если не осталось дробной части.
Функция printf ()
Доступ через функцию <stdio.h>
, функция printf()
является основным инструментом, используемым для печати текста на консоли в C.
printf("Hello world!");
// Hello world!
Обычные, неформатированные массивы символов могут быть напечатаны самим собой, помещая их непосредственно между круглыми скобками.
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
Альтернативно, целые числа, числа с плавающей запятой, символы и т. Д. Могут быть напечатаны с использованием escape-символа %
, за которым следует символ или последовательность символов, обозначающих формат, известный как спецификатор формата .
Все дополнительные аргументы функции printf()
разделяются запятыми, и эти аргументы должны быть в том же порядке, что и спецификаторы формата. Дополнительные аргументы игнорируются, а неверно введенные аргументы или отсутствие аргументов приводят к ошибкам или неопределенному поведению. Каждый аргумент может быть либо буквальным значением, либо переменной.
После успешного выполнения количество напечатанных символов возвращается с типом int
. В противном случае отказ возвращает отрицательное значение.
Модификаторы длины
Стандарты C99 и C11 определяют следующие модификаторы длины для printf()
; их значения:
Модификатор | Модифицирует | Относится к |
---|---|---|
чч | d, i, o, u, x или X | char , signed char или unsigned char |
час | d, i, o, u, x или X | short int или unsigned short int |
L | d, i, o, u, x или X | long int или unsigned long int |
L | a, A, e, E, f, F, g или G | double (для совместимости с scanf() ; undefined в C90) |
Л.Л. | d, i, o, u, x или X | long long int или unsigned long long int |
J | d, i, o, u, x или X | intmax_t или uintmax_t |
Z | d, i, o, u, x или X | size_t или соответствующий тип ssize_t ( ssize_t в POSIX) |
T | d, i, o, u, x или X | ptrdiff_t или соответствующий целочисленный тип без знака |
L | a, A, e, E, f, F, g или G | long double |
Если модификатор длины появляется с любым спецификатором преобразования, отличным от указанного выше, поведение не определено.
Microsoft указывает некоторые модификаторы длины и явно не поддерживает hh
, j
, z
или t
.
Модификатор | Модифицирует | Относится к |
---|---|---|
I32 | d, i, o, x или X | __int32 |
I32 | o, u, x или X | unsigned __int32 |
I64 | d, i, o, x или X | __int64 |
I64 | o, u, x или X | unsigned __int64 |
я | d, i, o, x или X | ptrdiff_t (то есть __int32 на 32-битных платформах, __int64 на 64-битных платформах) |
я | o, u, x или X | size_t (то есть unsigned __int32 на 32-битных платформах, unsigned __int64 на 64-битных платформах) |
л или L | a, A, e, E, f, g или G | long double (В Visual C ++, хотя long double является отдельным типом, он имеет то же внутреннее представление, что и double ). |
l или w | c или C | Широкий характер с функциями printf и wprintf . ( lc , lC , wc или wC является синонимом функций C в printf и c функциями wprintf .) |
l или w | s, S или Z | Широкосимвольная строка с функциями printf и wprintf . ( wS типа ls , lS , ws или wS является синонимом S в функциях printf и с s в функциях wprintf .) |
Обратите внимание, что спецификаторы преобразования C
, S
и Z
и модификаторы I
, I32
, I64
и w
length являются расширениями Microsoft. Обработка l
в качестве модификатора для long double
а не double
, отличается от стандарта, хотя вам будет трудно определить разницу, если long double
имеет другого представления из double
.
Флаги формата печати
Стандарт C (C11 и C99 тоже) определяет следующие флаги для printf()
:
Флаг | Конверсии | Имея в виду |
---|---|---|
- | все | Результат преобразования должен быть оставлен по полю в поле. Преобразование является правильным, если этот флаг не указан. |
+ | числовое число | Результат подписанного преобразования всегда начинается со знака ('+' или '-'). Преобразование начинается со знака только тогда, когда отрицательное значение преобразуется, если этот флаг не указан. |
<space> | числовое число | Если первый символ подписанного преобразования не является признаком или если подписанное преобразование не приводит к символам, в результат должен быть префикс <space> . Это означает, что при появлении флагов <space> и ' + ' флаг <space> игнорируется. |
# | все | Указывает, что значение должно быть преобразовано в альтернативную форму. Для преобразования o , оно должно увеличивать точность, если и только если необходимо, чтобы заставить первую цифру результата быть нулевой (если значение и точность равны 0, выводится один 0). Для спецификаторов преобразования x или X ненулевой результат должен иметь префикс 0x (или 0X ). Для спецификаторов преобразования a , A , e , E , f , F , g и G результат всегда должен содержать знак радиуса, даже если никакие цифры не следуют за символом radix. Без этого флага в результате этих преобразований появляется символ радиуса, только если после него следует цифра. Для спецификаторов преобразования g и G конечные нули не должны удаляться из результата, как обычно. Для других спецификаторов преобразования поведение не определено. |
0 | числовой | Для d, i, o, u, x, X, a, A, e, E, f, F, g и G спецификаторов преобразования, ведущие нули (после любого указания знака или основания) используются для заполнения поля ширину, а не выполнение пробела, за исключением того, что при преобразовании бесконечности или NaN. Если появляются флаги «0» и «-», флаг «0» игнорируется. Для спецификаторов преобразования d, i, o, u, x и X, если задана точность, флаг «0» игнорируется. ⌦ Если появляются флаги '0' и <apostrophe> , символы группировки вставляются перед нулевым заполнением. Для других преобразований поведение не определено. ⌫ |
Эти флаги также поддерживаются Microsoft с тем же значением.
Спецификация POSIX для printf()
добавляет:
Флаг | Конверсии | Имея в виду |
---|---|---|
' | i, d, u, f, F, g, G | Целочисленная часть результата десятичного преобразования должна быть отформатирована тысячами символов группировки. Для других преобразований поведение не определено. Используется символ неденежной группировки. |