sprintf () без завершающего нулевого пространства в C

Есть ли способ использовать функцию C sprintf () без добавления символа «\ 0» в конце ее вывода? Мне нужно написать форматированный текст в середине строки фиксированной ширины.

10.12.2008 18:29:24
8 ОТВЕТОВ
РЕШЕНИЕ

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

43
10.12.2008 18:44:19
Или используйте memmove () или возможно memcpy () вместо strncpy ().
Jonathan Leffler 10.12.2008 18:59:40
Roddy: функция snprintf всегда возвращает ноль в конец. Если вы передадите snprintf размер n, он запишет не более n-1 символов, за которыми следует завершающий символ '\ 0'.
Greg Hewgill 11.12.2008 18:21:40
На самом деле этот пример не добавляет ноль: char name [9] = "QQ40dude"; без знака int i0To100 = 63; _snprintf (& название [2], 2, "% d", i0To100); printf (name); // output: QQ63dude
yan bellavance 21.02.2015 18:24:21
@yanbellavance: Ваш пример не работает, как вы утверждаете, и печатает просто QQ6.
Greg Hewgill 23.02.2015 18:12:42

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

 unsigned int len = sprintf(str, ...);
 str[len] = '<your char here>';
26
10.12.2008 21:11:59

Вы также можете использовать строку фиксированной ширины в качестве строки формата, например:

char my_fixed_width_string_format[] = "need 10 chars starting here: %10s";
char my_fixed_width_string[40];
char string_to_print[] = "abcdefghijklmnop";
sprintf(my_fixed_width_string, my_fixed_width_string_format, string_to_print;
printf(my_fixed_width_string);

должен уступить

нужно 10 символов, начиная с здесь: abcdefghij

2
11.12.2008 07:52:24
Это, наверное, лучший способ сделать это.
pjc50 4.10.2010 13:41:32
Это предотвращает завершающий нуль от sprintf ()? или значение в my_fixed_width_string + 41 перекрывается нулем?
Bryan P 31.08.2013 05:44:55

Вы не можете сделать это с помощью sprintf (), но вы можете сделать это с помощью snprintf (), в зависимости от вашей платформы.

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

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

char message[32] = "Hello 123, it's good to see you.";

snprintf(&message[6],3,"Joe");

После этого «123» заменяется на «Джо».

В реализациях, где snprintf () гарантирует нулевое завершение, даже если строка обрезана, это не будет работать. Так что, если переносимость кода является проблемой, вам следует избегать этого.

Большинство версий snprintf () для Windows демонстрируют такое поведение.

Но MacOS и BSD (и, возможно, linux) всегда заканчиваются нулем.

4
4.02.2009 16:04:11
Функция snprintf всегда нулевая завершает свой вывод. После запуска приведенного выше кода сообщение содержит «Hello Jo».
Greg Hewgill 11.12.2008 18:24:21
@Greg. Вы почти правы ... Я обновил ответ, чтобы отразить зависимость реализации.
Roddy 11.12.2008 22:28:50
Вау, я никогда не знал, что это может отличаться для разных платформ, спасибо за это.
Greg Hewgill 12.12.2008 05:40:56
Кто-нибудь знает, что диктуют спецификации POSIX и / или C99?
Tommy 26.10.2010 10:13:47
Я полагаю, что спецификации предписывают всегда добавлять нулевой терминатор (идея заключается в том, что строки всегда заканчиваются нулем и находятся в пределах границ, что предотвращает переполнение буфера). Однако большинство реализаций отличаются от стандартных либо отсутствием добавления \ 0, либо добавлением его после конца буфера. Смотрите википедию: printf.
sam 9.02.2011 12:06:50

смотрите здесь: http://en.wikipedia.org/wiki/Printf

printf ("%. * s", 3, "abcdef") приведет к печати "abc"

-2
4.10.2010 13:38:54
строковые версии этих функций отличаются в этом отношении от нестроковых версий. Другими словами, sprintf и snprintf всегда добавляют нулевой байт, а printf - нет, поэтому ваш пример неприменим.
Todd Freed 3.07.2012 22:56:49

Поскольку вы пишете в фиксированную область, вы можете сделать это следующим образом:

// pointer to fixed area we want to write to
char* s;

// number of bytes needed, not including the null
int r = snprintf(0, 0, <your va_args here>);

// char following the last char we will write - null goes here
char c = s[r + 1];

// do the formatted write
snprintf(s, r + 1, <your_va_args here>);

// replace what was overwritten
s[r + 1] = c;
0
3.07.2012 23:01:47

На самом деле этот пример не добавит ноль, если вы используете snprintf:

char name[9] = "QQ40dude";  
unsigned int i0To100 = 63;  
_snprintf(&name[2],2,"%d",i0To100);  
printf(name);// output will be: QQ63dude  
0
21.02.2015 18:26:33
К сожалению, выход QQ6с POSIX snprintf(3).
nodakai 26.05.2015 07:44:06

Вот вариант для устройств с ограниченным объемом памяти. Он меняет скорость за использование меньшего количества оперативной памяти. Иногда мне приходится делать это, чтобы обновить середину строки, которая выводится на ЖК-дисплей.

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

Вы можете запустить следующий код здесь: https://rextester.com/AMOOC49082

#include <stdio.h>
#include <string.h>

int main(void)
{
  char buf[100] = { 'a', 'b', 'c', 'd', 'e' };
  const size_t buf_size = sizeof(buf);
  const int i = 123;

  int result = snprintf(buf, 0, "%i", i);
  if (result < 0)
  {
    printf("snprintf error: %i\n", result);
    return -1;
  }

  int clobbered_index = result; //this index will get the null term written into it

  if (result >= buf_size)
  {
    printf("buffer not large enough. required %i chars\n", result + 1);
    return -1;
  }

  char temp_char = buf[clobbered_index];
  result = snprintf(buf, buf_size, "%i", i); //add result error checking here to catch future mistakes
  buf[clobbered_index] = temp_char;

  printf("buf:%s\n", buf);

  return 0;
}

Печать buf:123de

0
27.12.2019 21:56:23