Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > sprintf и нулевой символ


Автор: Fedor 6.1.2007, 13:57
Рассмотрим простенький примерчик:
Код

#include <stdio.h>
void main()
{
   char a = '\0';
   char buf[100];

   printf( "printf: %0cTest\n", a );
   sprintf( buf, " sprintf: %0cTest2\n", a );
   printf( "%s", buf );
}

Компилим например в cc, gcc, xLc, etc.

В случае printf нулевой символ пропускается, и слово Test выводится на ура.
В случае sprintf, нулевой символ пишется в buf, и соответственно на экран все что за ним не выводится.

В общем, что сие? Почему различия в поведении? Баг, фича, что-то еще? В стандарте С что-нибудь сказано по сему поводу?

Автор: Sartorius 6.1.2007, 14:06
 ИМХО не баг и не фича. В первом случае format string должна пропарситься целиком, независимо от того , что будет выводиться. А во втором случае - нопмальный вывод zerro-string . Усе логично.

ЗЫ не следует думать, что при printf сначала формируется где то буффер , содержащий вывод, а потом выводится эта строка

Автор: WERITAS 6.1.2007, 14:14
Код

В случае printf нулевой символ пропускается, и слово Test выводится на ура.
В случае sprintf, нулевой символ пишется в buf, и соответственно на экран все что за ним не выводится.


Все правильно! На то он и нулевой символ. 
printf выводит строчку на экран. Там не обрывается вывод. Так и надо.  А в другом случае  sprintf копирует в буфер.  Т.е. ты конец строки вставил в начало строки, поэтому ничего и не выводится.


О5 опередили!  smile 

Автор: W4FhLF 6.1.2007, 14:28
Цитата(Fedor @  6.1.2007,  13:57 Найти цитируемый пост)
В общем, что сие? Почему различия в поведении? Баг, фича, что-то еще? В стандарте С что-нибудь сказано по сему поводу?


Не знаю как насчёт стандарта, но вот 10 минут в отладчике помогли сделать такие выводы:


Цитата

printf( "printf: %0cTest\n", a );


Функция СНАЧАЛА определяет длину формата(т.е. printf: %0cTest\n), она равна 0xE, ПОСЛЕ чего она делает подстановку всех переменных. Т.е. на этом этапе мы имеем в буфере:

Цитата

00155170  70 72 69 6E 74 66 3A 20 00 54 65 73 74 0A        printf: .Test.


И в функцию CRTDLL._write передаётся указатель на буфер и длина ФОРМАТА, т.е. 0xE, а не 0x8 как может показаться. 

Цитата

sprintf( buf, " sprintf: %0cTest2\n", a );


Определяется длина формата, идёт подстановка переменных и копирование в буфер того кол-ва байт, которое равно длине формата.

Цитата

printf( "%s", buf );


При парсинге формата программа находит %s, далее программа берёт первую переменную из списка, т.е. buf и определяет её длину путём поиска \0 в строке, именно эта величина считается размером буфера при передаче параметров функции CRTDLL._write, любой текст после символа \0 не учитывается, т.к. концов строки(%s) является именно он.

Ну так, в общих чертах, что непонятно спрашивайтеsmile

Добавлено @ 14:28 
Опередили засранцыsmile

Автор: Fedor 6.1.2007, 15:08
Sartorius, WERITAS, W4FhLF, всем спасибо. Логику осознал.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)