Нет, код, который вы написали, не работает. Официально говоря, это undefined-behavior. Вы не должны передавать объекты функциям с переменным числом аргументов. Эти типы функций не имеют проверки типов во время компиляции (т.е., не безопасны для типов), поэтому компилятор не знает, что он должен вызвать неявный оператор преобразования для преобразования этого CString
возражать против PCXSTR
. Вы должны выполнить преобразование явно, либо с помощью приведения, либо с помощью вызова функции-члена, которая возвращает указатель на базовый строковый буфер в стиле C.
Это верно для всех функций с переменным числом переменных. Даже что-то такое простое, как printf
. Следующий код неверен:
std::string str = "world";
printf("Hello, %s", str); // <-- this code is WRONG!
Вы должны написать это так:
std::string str = "world";
printf("Hello, %s", str.c_str());
Это было бы то же самое для MFC*:
CString str = TEXT("world");
CString buffer;
buffer.Format(TEXT("Hello, %s"), static_cast<LPCTSTR>(str));
// alternatively:
// buffer.Format(TEXT("Hello, %s"), str.GetString());
Это хорошая причина не использовать функции с переменным числом переменных в C++. Предпочитайте потоки, которые являются типобезопасными и делают правильные вещи.
Предупреждение, которое вы получаете, пытается предупредить вас об этой проблеме. Несмотря на то, что вариативные функции не являются типобезопасными, это настолько распространенная проблема, что поставщики компиляторов приложили много усилий, чтобы попытаться проанализировать строку формата, найти вставки и сопоставить их с передаваемыми аргументами. В этом случае обнаружено несоответствие по причинам, которые я описал, и выдается предупреждение C6284.
* На самом деле, в данном случае это работает в любом случае для CString. Это связано с тем, что, как вы обнаружили в отладчике, класс был разработан специально таким образом, чтобы его первый член был указателем на строковый буфер в стиле C. Следовательно, когда он передается по значению небезопасным способом в функцию с переменным числом аргументов, такую как printf
, единственное, что видит printf
, — это указатель, поэтому он правильно анализируется, когда видит спецификатор %s
. Но я бы не рекомендовал полагаться на такое поведение. Это по-прежнему формально неопределенное поведение, даже если оно работает в зависимости от реализации.
документация Microsoft конкретно говорит вам передавать объекты CString в вариативные функции, выполняя явное приведение к указателю на символ.
Конечно, маловероятно, что интерфейс CString изменится на этом этапе, и еще менее вероятно, потому что это нарушит так много существующего кода. Но вы никогда не знаете, и это делает ваши намерения более ясными, когда вы пишете код правильно.
person
Cody Gray
schedule
09.08.2016