From bc5d07ab2a8493b5b343f9f661d3529e6b33ad2d Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sat, 21 Mar 2015 16:01:16 +0300 Subject: [PATCH] snprintf() fix --- libuavcan/include/uavcan/build_config.hpp | 8 +++++ libuavcan/include/uavcan/std.hpp | 42 ++++++++++++++++++----- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/libuavcan/include/uavcan/build_config.hpp b/libuavcan/include/uavcan/build_config.hpp index eab0e386fe..13a6725f4d 100644 --- a/libuavcan/include/uavcan/build_config.hpp +++ b/libuavcan/include/uavcan/build_config.hpp @@ -134,6 +134,14 @@ # define UAVCAN_IMPLEMENT_PLACEMENT_NEW 0 #endif +/** + * Allows the user's application to provide custom implementation of uavcan::snprintf(), + * which is often useful on deeply embedded systems. + */ +#ifndef UAVCAN_USE_EXTERNAL_SNPRINTF +# define UAVCAN_USE_EXTERNAL_SNPRINTF 0 +#endif + /** * Run time checks. * Resolves to the standard assert() by default. diff --git a/libuavcan/include/uavcan/std.hpp b/libuavcan/include/uavcan/std.hpp index 9e1cbc9a84..c04ced0c89 100644 --- a/libuavcan/include/uavcan/std.hpp +++ b/libuavcan/include/uavcan/std.hpp @@ -2,11 +2,11 @@ * Copyright (C) 2014 Pavel Kirienko */ -#ifndef UAVCAN_STDINT_HPP_INCLUDED -#define UAVCAN_STDINT_HPP_INCLUDED +#ifndef UAVCAN_STD_HPP_INCLUDED +#define UAVCAN_STD_HPP_INCLUDED #include -#include +#include #if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11) # error UAVCAN_CPP_VERSION @@ -20,8 +20,6 @@ namespace uavcan { -using std::snprintf; // Can be used to replace standard snprintf() with a user-provided one. - typedef std::uint8_t uint8_t; typedef std::uint16_t uint16_t; typedef std::uint32_t uint32_t; @@ -37,13 +35,11 @@ typedef std::int64_t int64_t; #else # include // Standard integer types from C library -# include // snprintf() from the C library +# include // vsnprintf() from the C library namespace uavcan { -using ::snprintf; - typedef ::uint8_t uint8_t; typedef ::uint16_t uint16_t; typedef ::uint32_t uint32_t; @@ -58,4 +54,32 @@ typedef ::int64_t int64_t; #endif -#endif // UAVCAN_STDINT_HPP_INCLUDED +namespace uavcan +{ +/** + * Wrapper over the standard snprintf(). This wrapper is needed because different standards and different + * implementations of C++ do not agree whether snprintf() should be defined in std:: or in ::. The solution + * is to use 'using namespace std' hack inside the wrapper, so the compiler will be able to pick whatever + * definition is available in the standard library. Alternatively, the user's application can provide a + * custom implementation of uavcan::snprintf(). + */ +#if __GNUC__ +__attribute__ ((format(printf, 3, 4))) +#endif +extern int snprintf(char* out, std::size_t maxlen, const char* format, ...); + +#if !UAVCAN_USE_EXTERNAL_SNPRINTF +inline int snprintf(char* out, std::size_t maxlen, const char* format, ...) +{ + using namespace std; // This way we can pull vsnprintf() either from std:: or from ::. + va_list args; + va_start(args, format); + const int return_value = vsnprintf(out, maxlen, format, args); + va_end(args); + return return_value; +} +#endif + +} + +#endif // UAVCAN_STD_HPP_INCLUDED