Почему строка формата printf C имеет как %c, так и %s?


Почему строка формата printf C имеет оба %c и %s?

Я знаю, что %c представляет один символ и %s представляет строку символов с нулевым завершением, но разве одного строкового представления недостаточно?

11 69

11 ответов:

вероятно, чтобы различать нулевую завершенную строку и символ. Если бы они только имели %s, то каждый символ также должен быть null завершен.

char c = 'a';

В приведенном выше случае, c должен иметь значение null. Это мое предположение, хотя :)

%s выводит символы, пока он не достигнет 0 (или '', то же самое).

если у вас просто есть char x;, распечаткой с printf("%s", &x); -вы должны были бы предоставить адрес, так как %s ждет char* - даст неожиданные результаты, как &x + 1 не может быть 0.

таким образом, вы не могли просто напечатать один символ, если он не был null-terminated (очень неэффективно).

EDIT: как указывали другие, эти два ожидайте разных вещей в параметрах var args - один указатель, другой один символ. Но эта разница несколько ясна.

проблема, которая упоминается другими, что один символ должен быть null завершен, не является реальным. С этим можно было бы справиться, предоставив точность формату %.1s будет делать трюк.

что более важно, на мой взгляд, это то, что для %s в любой из его форм вам придется предоставить указатель на один или несколько символов. Это означало бы, что вы не сможете печатать rvalues (вычисляемые выражения, возвращаемые функции и т. д.) или регистрировать переменная.

Edit: я очень зол на реакцию на этот ответ, поэтому я, вероятно, удалю это, это действительно не стоит. Кажется, что люди реагируют на это, даже не прочитав вопрос или не зная, как оценить техническую сторону вопроса.

чтобы было ясно: я не говорю, что вы должны предпочесть %.1s over %c. Я только говорю, что причины %c не могут быть заменены тем, что отличаются от другой ответ делают вид, что говорят. Эти другие ответы просто технически неверно. Нулевое завершение не является проблемой с %s.

функция printf является вариативной функцией, что означает, что она имеет переменное число аргументов. Аргументы помещаются в стек перед вызовом функции (printf). Для того чтобы функция printf использовала стек, ей необходимо знать информацию о том, что находится в стеке, для этого используется строка формата.

например

printf( "%c", ch );    tells the function the argument 'ch' 
                       is to be interpreted as a character and sizeof(char)

, тогда как

printf( "%s", s );   tells the function the argument 's' is a pointer 
                     to a null terminated string sizeof(char*)

внутри функции printf невозможно иначе определить содержимое стека например, различение между " ch " и "s", потому что в C нет проверки типа во время выполнения.

%s говорит, что печатает все символы, пока вы не найдете null (рассматривайте переменную как указатель).

%c говорит печатать только один символ (рассматривать переменную как код символа)

используя %s для символа не работает, потому что символ будет рассматриваться как указатель, то он будет пытаться напечатать все символы, следующие за этим местом в памяти, пока не найдет null

кража из других ответов to объясните это по-другому.

если вы хотите напечатать символ с помощью %s, вы можете использовать следующее, Чтобы правильно передать ему адрес символа и не дать ему писать мусор на экране до тех пор, пока не найдете null.

char c = 'c';
printf('%.1s', &c);

на %s, нам нужно указать адрес строки, а не ее значение.

на %c, мы предоставляем значение символов.

если используется %s вместо %c, как бы мы предоставляем '' после символов?

Id хотел бы добавить еще одну точку зрения на этот интересный вопрос.

на самом деле это сводится к типизации данных. Я видел ответы здесь, что вы можете предоставить указатель на символ и предоставить

"%.1s"

Это действительно может быть правдой. Но ответ заключается в том, что дизайнер C пытается обеспечить гибкость программисту, и действительно (хотя и небольшой) способ уменьшить площадь вашего приложения.

иногда программист может например, запустить серию операторов if-else или switch-case, где нужно просто вывести символ на основе состояния. Для этого жесткое кодирование символов действительно может занять меньше фактического пространства в памяти, поскольку одиночные символы составляют 8 бит по сравнению с указателем, который составляет 32 или 64 бита (для 64-разрядных компьютеров). Указатель займет больше места в памяти.

Если вы хотите уменьшить размер с помощью фактических символов по сравнению с указателями на символы, то есть два способа можно было бы подумать, чтобы сделать это в типах printf операторов. Одним из них было бы отключить ключ .1s, но как подпрограмма должна знать наверняка, что вы действительно предоставляете тип char по сравнению с указателем на char или указателем на строку (массив символов)? Вот почему они пошли с "%c", так как он отличается.

Забавный Вопрос :-)

С %c и %s спецификаторы формата, потому что они обрабатывают разные типы.

A char и строка примерно такие же разные, как ночь и 1.

%c ожидает char, который является целым числом стоимостью и печатает его в соответствии с правилами кодирования.

%s ожидает a указатель в ячейку памяти, которая содержит char значения, и печатает символы в этом месте в соответствии с правилами кодирования, пока не найдет 0 (нуль) характер.

Так что вы видите, под капотом, два случая, хотя они выглядят одинаково они не имеют много общего, как один работает со значениями, А другой с указатели. Одна из них-инструкции для интерпретации определенного целочисленного значения как символа ascii, а другая-итерация содержимого символа ячейки памяти по символу и интерпретация их до тех пор, пока не будет найдено нулевое значение.

Я провел эксперимент с printf("%.1s", &c) и printf("%c", c). Я использовал код ниже, чтобы проверить, и Баш time утилита получить время выполнения.

    #include<stdio.h>
    int main(){
        char c = 'a';
        int i;
        for(i = 0; i < 40000000; i++){
            //printf("%.1s", &c); get a result of 4.3s
            //printf("%c", c); get a result of 0.67s
        }
        return 0;
    }

результат говорит, что с помощью %c в 10 раз быстрее, чем %.1s. Таким образом, хотя %s может выполнять работу %c, %c по-прежнему необходим для производительности.

поскольку никто не предоставил ответ с какой-либо ссылкой вообще, вот спецификация printf от pubs.opengroup.com который похож на определение формата из IBM

%c

аргумент int должен быть преобразован в символ без знака, и полученный байт должен быть записан.

%s

аргумент должен быть указателем на массив символов. Байты из массива должны быть записывается до (но не включая) любого завершающего нулевого байта. Если задана точность, то записывается не более этого количества байтов. Если точность не указана или превышает размер массива, приложение должно убедиться, что массив содержит нулевой байт.