Поиск…


Печать значения указателя на объект

Чтобы напечатать значение указателя на объект (в отличие от указателя функции), используйте спецификатор преобразования 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;
}
C99

Использование <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 . Непонятно, почему вы когда-либо хотели обрабатывать адреса как целые числа.

K & R C89

Предварительная стандартная история:

До 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 длины.

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;
}

Результат может выглядеть так:

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 Целочисленная часть результата десятичного преобразования должна быть отформатирована тысячами символов группировки. Для других преобразований поведение не определено. Используется символ неденежной группировки.


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow