Использование printf со строкой, не завершающейся нулем
108
Предположим, у вас есть строка, которая НЕ nullзаканчивается, и вы знаете ее точный размер, так как же вы можете распечатать эту строку с помощью printfC? Я припоминаю такой метод, но сейчас не могу узнать ...
Но в любом случае это опасно, кто-нибудь когда-нибудь напечатает эту строку с помощью% s
pmod
6
@Pmod: Не обязательно, если буфер не открыт для внешнего мира. Также очень полезно просто печатать части строки (которая, конечно, может оканчиваться нулем). Если вы действительно хотите увидеть это в действии, взгляните на прокси-сервер OpenSER / Kamailio SIP, где они часто избегают копирования материала из-за этой техники (также с использованием sprintf).
DarkDust
6
еще +1. Мне нравится, когда я узнаю что-то об элементарных вещах, например, printfдаже через ~ десятилетие ... :)
Hertzel Guinness
1
Для меня это очень полезно, когда я получаю от API строку, не завершающуюся нулевым символом (некоторые API Windows делают это!), И должен возвращать ее «разумным» способом. Итак: долгая жизнь%. * S (или%. * S, который также сделает преобразование UNICODE <-> SINGLE-BYTE для вас!;))
FrizzTheSnail
3
@ user1424739: В вашем случае printfбудет печатать до 11 символов или пока не встретится NULL, в зависимости от того, что наступит раньше; в вашем примере сначала идет NULL. Указание максимальной длины не приводит к тому, что NULL теряет свое значение "конец строки" printf.
DarkDust
31
Вот объяснение того, как это %.*sработает, и где это указано.
Спецификации преобразования в строке шаблона printf имеют общий вид:
%[ param-no $] flags width [. precision ] type conversion
или
%[ param-no $] flags width .*[ param-no $] type conversion
Вторая форма предназначена для получения точности из списка аргументов:
Вы также можете указать точность «*». Это означает, что следующий аргумент в списке аргументов (перед фактическим значением, которое будет напечатано) используется в качестве точности. Значение должно быть целым числом и игнорируется, если оно отрицательное.
Для %sформатирования строк точность имеет особое значение:
Можно указать точность, чтобы указать максимальное количество символов для записи; в противном случае символы в строке до завершающего нулевого символа, но не включая его, записываются в выходной поток.
Если я правильно понимаю, следующее будет дополнять вывод, но все же предотвращает переполнение строки? "%-*.*s", padding, str_view.size(), str_view.data()
Таким образом вы выведете первые символы (число, определенное в переменной number_of_chars) в файл, в данном случае на стандартный вывод (стандартный вывод, ваш экран)!
Очень полезно, если вы хотите проверить длинный буфер, содержащий строки и нули!
Elist
13
printf("%.*s", length, string) не будет работать.
Это означает, что нужно печатать до байтов длины ИЛИ нулевой байт, в зависимости от того, что наступит раньше. Если ваш массив символов без завершающего нуля содержит нулевые байты ДО длины, printf остановится на них и не продолжит работу.
если он не оканчивается нулем, то null является допустимым символом для содержащейся строки. это по-прежнему считает, что массив завершается нулем, он просто рассматривает его как более длинный массив, из которого он выбирает подвыбор - что означает, что если у вас есть строка с нулями в ней, это вызовет проблемы.
#include<string.h>int main(){/*suppose a string str which is not null terminated and n is its length*/int i;for(i=0;i<n;i++){
printf("%c",str[i]);}return0;}
Я отредактировал код, вот другой способ:
#include<stdio.h>int main(){
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/return0;}
Очень низкая производительность из-за большого количества ненужных чтений байтов (что приводит к снижению производительности, если байт не находится в адресе, выровненном по словам на большинстве процессоров), а также синтаксический анализ и применение форматирования выполняется для каждого символа. Не делайте этого :-) Решение см. В моем ответе.
DarkDust
@DarkDust: только патологическая машина будет наказывать чтение байтов, не выровненное по границам слова. Вы думаете, что чтение слов не совпадает с границами слов? Или какая-то древняя хрень мипса, что ли?
R .. GitHub ПРЕКРАТИТЕ ПОМОЩЬ ICE
@R ..: Если вы считаете, что x86 поврежден мозгом и устарел, я полностью согласен. Потому что x86 имеет штраф за чтение и запись памяти без выравнивания слов. ARM тоже. См., Например, этот вопрос или этот вопрос . Дело в том (если я правильно понял), что данные извлекаются из памяти кусками размером с слово, и получение правильного байта - это еще одна микрооперация. Ничего страшного, но в огромном цикле это может иметь значение.
DarkDust
@DarkDust: вы совершенно неправы насчет чтения байтов. Почему бы тебе не пройти тест? x86 имеет полностью атомарные байтовые операции и всегда имел. Он не извлекает фрагменты размером с слово (кроме уровня кеша, который извлекает гораздо большие фрагменты, и выравнивание не имеет значения, но я говорю об уже кэшированных данных).
R .. GitHub НЕ ПОМОГАЕТ ICE
@DarkDust: PS3 не поддерживает чтение и запись невыровненных байтов на SPU. Фактически он даже не поддерживает скалярные типы, есть только векторные, которые необходимо выровнять. Компилятор имитирует их. И многие процессоры ARM не поддерживают чтение или запись байтов, а только выполняют чтение или запись слова.
C
контексте все строки заканчиваются нулем. Массивы char без нуля в них не являются строками ... это массивы char :)Ответы:
Есть возможность с printf, это выглядит так:
Не нужно ничего копировать, не нужно изменять исходную строку или буфер.
источник
printf
даже через ~ десятилетие ... :)printf
будет печатать до 11 символов или пока не встретится NULL, в зависимости от того, что наступит раньше; в вашем примере сначала идет NULL. Указание максимальной длины не приводит к тому, что NULL теряет свое значение "конец строки"printf
.Вот объяснение того, как это
%.*s
работает, и где это указано.Вторая форма предназначена для получения точности из списка аргументов:
- Синтаксис преобразования вывода в руководстве по glibc
Для
%s
форматирования строк точность имеет особое значение:- Другие преобразования вывода в руководстве по glibc
Другие полезные варианты:
"%*.*s", maxlen, maxlen, val
будет выравниваться по правому краю, вставляя пробелы перед;"%-*.*s", maxlen, maxlen, val
будет выравнивать по левому краю.источник
"%-*.*s", padding, str_view.size(), str_view.data()
Вы можете использовать fwrite () в stdout!
Таким образом вы выведете первые символы (число, определенное в переменной number_of_chars) в файл, в данном случае на стандартный вывод (стандартный вывод, ваш экран)!
источник
printf("%.*s", length, string)
не будет работать.Это означает, что нужно печатать до байтов длины ИЛИ нулевой байт, в зависимости от того, что наступит раньше. Если ваш массив символов без завершающего нуля содержит нулевые байты ДО длины, printf остановится на них и не продолжит работу.
источник
Длина строки будет 5.
источник
Я отредактировал код, вот другой способ:
источник