Подтвердить что ты не робот

Могут ли входные и выходные строки для sprintf() быть одинаковыми?

Я использовал этот тип соглашения много раз в моем коде в прошлом:

strcpy ( cTmpA, "hello" );
sprintf ( cTmpA, "%s world", cTmpA );

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

Является ли приведенный выше код действительным K & R C? Если нет, как мне найти все места в моем коде, где произошел этот тип вызова sprintf()?

4b9b3361

Ответ 1

Пока это действительно K & R C, вы, вероятно, хотите узнать, действительно ли он POSIX - см. спецификацию sprintf. Мы читаем:

Если копирование происходит между объектами, которые перекрываются в результате вызова sprintf() или snprintf(), результаты undefined.

Ответ 2

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

И вы действительно должны использовать snprintf(), который защищает вас от переполнения буфера.

Чтобы найти все вызовы, поместите #define sprintf +++ в общий заголовок, найдите и перекомпилируйте все источники. Это должно дать вам список ошибок вместе с именем файла и номерами строк:) Или использовать рекурсивный поиск в вашей среде IDE.

Если вы хотите обрезать этот список до тех, где вы используете один и тот же указатель для обоих аргументов, используйте этот макрос:

#define sprintf(output,format,...) check_sprintf(__FILE__,__LINE__,output,format,....)

Обратите внимание, что не все компиляторы поддерживают макросы с помощью varargs. Затем определите новую функцию check_sprintf:

int check_sprintf (char*filename,int line,char*output,char*format,...) {
    va_list args;
    int len;

    if(output==format) {
        fprintf(stderr,
             "Output and format are the same at %s:%d", filename, line);
             abort();
    }

    va_start (args, format);
    len = vsprintf (output, format, args);
    va_end (args);

    return len;   
}

[EDIT] Я только что увидел, что вы говорите о выходе и первом аргументе. Вы можете повторно использовать код сверху и вызвать va_arg(), чтобы получить первый аргумент и использовать его в сравнении.