#c #printf #implicit-conversion #string-literals
Вопрос:
Я новичок в C и в основном использовал следующие два формата printf
#include <stdio.h>
//Compiler version gcc 6.3.0
int main()
{
int c=5;
printf("Hello, World!n");
printf("%d",c);
return 0;
}
Но недавно я узнал, что есть еще один способ написания printf,т. Е. printf(указатель строки), чем этот формат так отличается от двух других, в нем нет кавычек и почему есть строка, вопрос может быть глупым, но постарайтесь понять, что я всего лишь новичок.
Комментарии:
1. На самом деле, это точно то же самое, что вы используете с
printf("Hello, World!n")
. И также обратите внимание, что на самом деле это не разные формыprintf
функции, просто в некоторых вы передаете дополнительные аргументы, а в некоторых-нет.2. Также обратите внимание (и это довольно важно): вы никогда не должны передавать переменную в качестве строки формата. Если вы используете
printf
с пользовательским вводом, что помешает пользователю указать спецификаторы формата во входных данных, что приведетprintf("%sn", user_input_string)
илиputs(user_input_string)
.3. существует только одно определение
printf
:int printf(const char *restrict format, ...);
. Просто прочитайте документацию4. Пожалуйста, обратите внимание, что
printf
это вариативная функция .
Ответ №1:
Хотя в вашем редакторе это выглядит по-другому, на самом деле это одно и то же.
Когда вы пишете
printf("Hello, World!n");
в вашем редакторе ваш компилятор в принципе изменит его на
char* hidden_unnamed_string = "Hello, World!n";
printf(hidden_unnamed_string);
Строка «Привет, мир!n» называется строковым литералом. Компилятор (автоматически) поместит его где-нибудь в памяти, а затем вызовет printf
с этим адресом памяти.
Вот пример из godbolt.org
С левой стороны у вас есть программа на языке Си, как она выглядит в вашем редакторе. Справа у вас есть скомпилированная программа.
Обратите внимание, что строка расположена за пределами блока кода и помечена символом LC0. Затем внутри блока кода LC0 загружается в edi (т. е. адрес/указатель на строку загружается в edi) непосредственно перед вызовом функции печати.
Также обратите внимание, что компилятор решил использовать puts
вместо printf
. Далее обратите внимание, что строка хранится без n
. Причина в том, что puts
в отличие printf
от автоматически добавляет n
.
Ответ №2:
Для начала вместо этого вызова printf
printf("Hello, World!n");
вы могли бы использовать вызов таких команд, как
puts( "Hello, World!" );
Строковый литерал "Hello, World!n"
внутренне представлен в виде массива символов, например
char string_literal[] =
{
'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 'n', ''
};
Массивы, используемые в выражениях, неявно преобразуются (за редкими исключениями) в указатели на их первые элементы.
Так что в этом звонке
printf("Hello, World!n");
массив символов, используемый в качестве аргумента вызова функции, преобразуется в указатель типа char *
на его первый элемент 'H'
. Вы можете представить себе, что следующим образом
printf( amp;"Hello, World!n"[0] );
Таким образом, функция имеет дело с указателем типа char *
. Вы могли бы сделать то же самое, введя промежуточную переменную
char *s = "Hello, World!n";
printf( s );
или
char *s = "Hello, World!n";
printf( "%s", s );
или
char *s = "Hello, World!";
printf( "%sn", s );
или
char *s = "Hello, World!";
puts( s );