Я пытаюсь добавить безопасный метод форматирования строк, аналогичный sprintf, с помощью макроса variadic и доставить его в качестве системного заголовка и общего объекта в SDK на основе Yocto. В зависимости от расположения файла заголовка во время компиляции наблюдается два разных поведения.
MyMacro.hpp
#ifndef MYMACRO_HPP
#define MYMACRO_HPP
extern std::string stringFormat( const char* fmt, ... ) __attribute__ ((format(printf, 1, 2)));
#define FORMAT_STRING( fmt, ...) stringFormat( fmt, ##__VA_ARGS__ )
#endif //MYMACRO_HPP
MyMacro.cpp
#include <cstdio>
#include <cstdarg>
#include <string>
#include <vector>
std::string stringFormat( const char* fmt, ... )
{
va_list args1;
va_start( args1, fmt );
va_list args2;
va_copy( args2, args1 );
std::vector<char> buf( 1 + std::vsnprintf( nullptr, 0, fmt, args1 ) );
va_end( args1 );
std::vsnprintf( buf.data( ), buf.size( ), fmt, args2 );
va_end( args2 );
return std::string( buf.data( ), buf.data( ) + buf.size( ) );
}
libMyMacro.so генерируется с помощью следующей команды:
g++ -Wall -std=gnu++0x -shared -fPIC -o libMyMacro.so MyMacro.cpp
Использование:
main.cpp
#include <cstdarg>
#include <string>
#include <cstdio>
#include "mytest/MyMacro.hpp"
int main()
{
std::string myString = FORMAT_STRING( "%s %s", "test" );
std::printf( "%s", myString.c_str( ) );
}
При компиляции main.cpp путем размещения MyMacro.hpp в / usr / mytest / выдает следующую ошибку, как и ожидалось:
sh-4.3$ g++ -Wall -Werror -std=gnu++0x -I /usr/ -L /usr/lib/ -lMyMacro main.cpp
In file included from main.cpp:5:0:
main.cpp: In function 'int main()':
/usr/mytest/MyMacro.hpp:6:67: error: format '%s' expects a matching 'char*' argument [-Werror=format=]
#define FORMAT_STRING( fmt, ...) stringFormat( fmt, ##__VA_ARGS__ )
^
main.cpp:9:28: note: in expansion of macro 'FORMAT_STRING'
std::string myString = FORMAT_STRING( "%s %s", "test" );
^
cc1plus: all warnings being treated as errors
Теперь, если MyMacro.hpp находится в папке / usr / include / mytest /, g ++ не сообщает об ошибке при компиляции с помощью следующей команды:
g++ -Wall -Werror -std=gnu++0x -I /usr/include/ -L /usr/lib/ -lMyMacro main.cpp
Почему разница в результатах компиляции зависит от расположения файла заголовка?
GCC настроен с помощью / usr / include и / usr / local / include в качестве пути к системному заголовку по умолчанию в этом SDK.
Чтобы сообщить об ошибке из системных заголовков, используйте параметр -Wsystem-headers, хотя это активирует предупреждения и ошибки во всех включенных системных заголовочных файлах:
g++ -Wall -Werror -Wsystem-headers -std=gnu++0x -I /usr/include/ -L /usr/lib/ -lMyMacro main.cpp
Задача ещё не решена.
Других решений пока нет …