2016-02-27 4 views
1

Я прочитал сообщение sprintf format specifier replace by nothing, и другие связанные, но не видели это специально.Помогает ли sprintf() задавать спецификаторы спецификаций?

До сегодняшнего дня я никогда не видел sprintf, используя только 2 аргумента.
Прототип моя система использует для sprintf() является:

int sprintf (char Target_String[], const char Format_String[], ...); 

При работе с некоторыми унаследованного кода, я натыкался на это: (упрощен для иллюстрации)

char toStr[30]; 
char fromStr[]={"this is the in string"}; 
sprintf(toStr, fromStr); 

Моя интерпретация прототипа является то, что второй аргумент должен состоять из const char[] и принимать стандартные спецификаторы формата ansi C such as these.

Но приведенный выше пример, похоже, работает отлично с строкой fromStr в качестве второго аргумента.
Является ли это чисто неопределенным поведением, что это работает ?, или это использование совершенно законно?

Я работаю над Windows 7, используя компилятор C99.

+0

По другой причине, я бы сказал, что код находится рядом с ошибкой - я бы ожидать 'голец fromStr [] = {"this in the string"}; 'должно быть' char fromStr [] = "это строка в строке"; '(no' {} '). Код компилируется, так как я уверен, что OP намеревается, но для меня это выглядит как 'char fromStr [] = {" this in the string "};' должен сделать массив из 1 'char' со значением указателя, преобразованного в 'char'. Я думаю, это правильно, но выглядит неправильно – chux

+0

@chux - Интересно. Я смотрел по-одному, пытаясь выяснить, какие режимы отказа, если таковые имеются, я мог бы найти. (вид связанный с _format string attack_, упомянутый в комментариях ниже). Я пробовал с '= {"% это строка в строке "};' которая была ошибочной с _unknown specifier_, затем снова с '= {"% cthis является строкой "};', которая потому, что% c является известным спецификатором , с ошибкой _ Недостаточно параметров_. оба из которых, похоже, подтверждают правду ответов ниже. Что касается использования скобок '{" ... "};', они не создают проблемы для меня. – ryyker

ответ

1

Поведение, которое вы наблюдаете, является правильным, строка формата не требуется для каких-либо спецификаторов преобразования. В этом случае список аргументов переменной длины, представленный ..., имеет длину 0. Это совершенно законно, хотя это, безусловно, менее эффективно, чем его эквивалент

strcpy(toStr, fromStr); 
+1

@ryyker. Две причины, по которым «sprintf», как это, не удалось, заключается в том, что буфер назначения имеет недостаточную длину или источник не был надлежащим образом завершен. Однако обе ситуации приведут к тому, что 'strcpy' также потерпит неудачу. – dasblinkenlight

+0

Вы должны убедиться, что у вас нет переполнения буфера во всех этих sprintfs и strcpys. Лучше использовать ** n ** варианты этих функций. – BitWhistler

1

Это совершенно законно код, но

  1. Если вы просто хотите, чтобы скопировать строку, используйте strcpy() вместо этого.
  2. Если вы работаете с пользовательским вводом, вы можете сделать себя уязвимым для format string attack.
1

Сводка для sprintf является:

int sprintf(char *str, const char *format, ...); 

Это означает, что 2 аргументы являются законным вариантом.

1

Это работает, потому что у вас нет никаких дополнительных параметров (то есть нет управляющего формата %) для печати.

Это никакой разницы, чем printf без второго параметра:

int printf (const char * format, ...); 

Это также работает, если вы не имеете никакого второго параметра:

printf(fromStr); 
2

совершенно законно. Вариантные аргументы являются необязательными.

В этом случае printf используется как strcpy, но анализирует строку fmt для% спецификаторов.

Я бы написал sprintf(toStr,"%s",fromStr);, поэтому он не должен разбирать эту длинную строку.

1

второй аргумент должен состоять из const char[]

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

Код, который вы отправили, не использует строку const как второй аргумент sprintf(), но преобразование из константы в const неявно; там нет необходимости беспокоиться.

принимающие спецификаторы формата стандарта ANSI C

"прием" не означает, что "требует". Указанная форматная строка не содержит спецификатора формата. Соответственно, функция вызывается только с двумя аргументами (нет значений для форматирования). В любом случае третий аргумент будет проигнорирован sprinf(), и многие современные компиляторы выдадут предупреждение об этом.


Update: Я не хочу, чтобы начать дискуссию о том, какие компиляторы являются современные и которые не являются.

Случается, что я использую компилятор по умолчанию на OSX 10.11, и это то, что он выводит:

axiac: ~/test$ cc -v 
Apple LLVM version 7.0.2 (clang-700.1.81) 
Target: x86_64-apple-darwin15.3.0 
Thread model: posix 
axiac: ~/test$ cc -o 1 1.c 
1.c:8:25: warning: data argument not used by format string [-Wformat-extra-args] 
    sprintf(x, "abc\n", n); 
       ~~~~~~~^
+0

Я добавил обновление к своему ответу. Не удалось добавить его в качестве комментария из-за форматирования. – axiac

+0

Я только что протестировал с помощью 'gcc версии 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)'. Он имеет флаг '-Wformat', который *« Проверяет вызовы на «printf» и «scanf» и т. Д., Чтобы убедиться, что предоставленные аргументы имеют типы, соответствующие указанной строке формата, и что преобразования, указанные в строке формата имеют смысл. "*. Возможно, ваш компилятор также выполняет такие проверки, но по умолчанию они не включены, и вам нужно копать после опций в документации :-) – axiac

 Смежные вопросы

  • Нет связанных вопросов^_^