BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsla_printf.h
Go to the documentation of this file.
1/// @file bsla_printf.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsla_printf.h -*-C++-*-
8#ifndef INCLUDED_BSLA_PRINTF
9#define INCLUDED_BSLA_PRINTF
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsla_printf bsla_printf
15/// @brief Provide a macro to indicate `printf`-style arguments.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsla
19/// @{
20/// @addtogroup bsla_printf
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsla_printf-purpose"> Purpose</a>
25/// * <a href="#bsla_printf-macros"> Macros </a>
26/// * <a href="#bsla_printf-description"> Description </a>
27/// * <a href="#bsla_printf-macro-reference"> Macro Reference </a>
28/// * <a href="#bsla_printf-usage"> Usage </a>
29/// * <a href="#bsla_printf-example-1-printf-like-function-that-returns-a-bsl-string-by-value"> Example 1: printf-Like Function That Returns a bsl::string by Value </a>
30///
31/// # Purpose {#bsla_printf-purpose}
32/// Provide a macro to indicate `printf`-style arguments.
33///
34/// # Macros {#bsla_printf-macros}
35///
36/// - BSLA_PRINTF(FMTIDX, STARTIDX): validate `printf` format and arguments
37/// - BSLA_PRINTF_IS_ACTIVE: defined if `BSLA_PRINTF` is active
38///
39/// @see bsla_annotations
40///
41/// # Description {#bsla_printf-description}
42/// This component provides a preprocessor macro that allows the
43/// designation of a given function argument as a `printf`-style format string,
44/// and arguments starting at a certain index in the argument list to be
45/// formatted according to that string.
46///
47/// ## Macro Reference {#bsla_printf-macro-reference}
48///
49///
50/// `BSLA_PRINTF(FMTIDX, STARTIDX)`:
51/// This annotation instructs the compiler to perform additional
52/// compile-time checks on so-annotated functions that take `printf`-style
53/// arguments, which should be type-checked against a format string.
54///
55/// - The `FMTIDX` parameter is the one-based index to the `const char *`
56/// format string. The `STARTIDX` parameter is the one-based index to
57/// the first variable argument to type-check against that format string.
58/// For example:
59/// @code
60/// extern int my_printf(void *obj, const char *format, ...) BSLA_PRINTF(2, 3);
61/// @endcode
62///
63/// `BSLA_PRINTF_IS_ACTIVE`:
64/// The macro `BSLA_PRINTF_IS_ACTIVE` is defined if `BSLA_PRINTF` expands
65/// to something with the desired effect; otherwise `BSLA_PRINTF_IS_ACTIVE`
66/// is not defined and `BSLA_PRINTF` expands to nothing.
67///
68/// ## Usage {#bsla_printf-usage}
69///
70///
71/// This section illustrates intended use of this component.
72///
73/// ### Example 1: printf-Like Function That Returns a bsl::string by Value {#bsla_printf-example-1-printf-like-function-that-returns-a-bsl-string-by-value}
74///
75///
76/// First, we define a function, `strPrintf`, that takes a variable number of
77/// arguments. The second argument is the format string, and we annotate it
78/// with `BSLA_PRINTF`:
79/// @code
80/// std::string strPrintf(size_t *numChars, const char *format, ...)
81/// BSLA_PRINTF(2, 3);
82/// std::string strPrintf(size_t *numChars, const char *format, ...)
83/// // Do a 'sprintf'-style write to a 'std::string' and return the string
84/// // by value. Ensure that the write can't overflow unless memory or
85/// // address space is exhausted. The specified '*numChars' is the number
86/// // of characters written, the specified 'format' is the 'printf'-style
87/// // format string, and the specified '...' is the variable-length list
88/// // of arguments to be formatted.
89/// {
90/// std::string ret = " ";
91///
92/// va_list ap;
93/// va_start(ap, format);
94///
95/// // 'vsnprintf' returns the number of characters that WOULD have been
96/// // written (not including the terminating '\0') had the buffer been
97/// // long enough.
98///
99/// *numChars = ::vsnprintf(&ret[0], 1, format, ap);
100/// va_end(ap);
101///
102/// ret.resize(*numChars + 1);
103///
104/// va_start(ap, format);
105/// *numChars = ::vsnprintf(&ret[0], *numChars + 1, format, ap);
106/// va_end(ap);
107///
108/// BSLS_ASSERT(::strlen(ret.c_str()) == *numChars);
109///
110/// ret.resize(*numChars);
111/// return ret;
112/// }
113/// @endcode
114/// Then, in `main`, we call the function correctly a couple of times:
115/// @code
116/// size_t len;
117/// std::string s;
118///
119/// s = strPrintf(&len, "%s %s %s %g\n", "woof", "meow", "arf", 23.5);
120/// assert("woof meow arf 23.5\n" == s);
121/// assert(19 == len);
122/// assert(len == s.length());
123///
124/// s = strPrintf(&len, "%s %s %s %s %s %s %s %s %s\n",
125/// "The", "rain", "in", "Spain", "falls", "mainly",
126/// "in", "the", "plain");
127/// assert("The rain in Spain falls mainly in the plain\n" == s);
128/// assert(44 == len);
129/// assert(len == s.length());
130/// @endcode
131/// Now, we call it with too many arguments and of the wrong type:
132/// @code
133/// s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
134/// @endcode
135/// Finally, we observe the compiler warnings with clang:
136/// @code
137/// .../bsla_printf.t.cpp:328:41: warning: format specifies type 'int' but the
138/// argument has type 'const char *' [-Wformat]
139/// s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
140/// ~~ ^~~~~
141/// %s
142/// .../bsla_printf.t.cpp:328:48: warning: format specifies type 'double' but
143/// the argument has type 'int' [-Wformat]
144/// s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
145/// ~~ ^~
146/// %d
147/// .../bsla_printf.t.cpp:328:52: warning: format specifies type 'double' but
148/// the argument has type 'int' [-Wformat]
149/// s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
150/// ~~ ^~
151/// %d
152/// .../bsla_printf.t.cpp:328:56: warning: data argument not used by format
153/// string [-Wformat-extra-args]
154/// s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
155/// ~~~~~~~~~~ ^
156/// @endcode
157/// @}
158/** @} */
159/** @} */
160
161/** @addtogroup bsl
162 * @{
163 */
164/** @addtogroup bsla
165 * @{
166 */
167/** @addtogroup bsla_printf
168 * @{
169 */
170
171#include <bsls_platform.h>
172
173 // =============================
174 // Checks for Pre-Defined macros
175 // =============================
176
177#if defined(BSLA_PRINTF)
178#error BSLA_PRINTF is already defined!
179#endif
180
181#if defined(BSLA_PRINTF_IS_ACTIVE)
182#error BSLA_PRINTF_IS_ACTIVE is already defined!
183#endif
184
185 // =========================
186 // Set macros as appropriate
187 // =========================
188
189
190#if defined(BSLS_PLATFORM_CMP_GNU) && !defined(BSLS_PLATFORM_CMP_CLANG)
191 #define BSLA_PRINTF(fmt, arg) __attribute__((format(gnu_printf, fmt, arg)))
192
193 #define BSLA_PRINTF_IS_ACTIVE 1
194#elif defined(BSLS_PLATFORM_CMP_CLANG) || \
195 defined(BSLS_PLATFORM_CMP_HP) || \
196 defined(BSLS_PLATFORM_CMP_IBM)
197 #define BSLA_PRINTF(fmt, arg) __attribute__((format(printf, fmt, arg)))
198
199 #define BSLA_PRINTF_IS_ACTIVE 1
200#else
201 #define BSLA_PRINTF(fmt, arg)
202#endif
203
204#endif
205
206// ----------------------------------------------------------------------------
207// Copyright 2019 Bloomberg Finance L.P.
208//
209// Licensed under the Apache License, Version 2.0 (the "License");
210// you may not use this file except in compliance with the License.
211// You may obtain a copy of the License at
212//
213// http://www.apache.org/licenses/LICENSE-2.0
214//
215// Unless required by applicable law or agreed to in writing, software
216// distributed under the License is distributed on an "AS IS" BASIS,
217// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
218// See the License for the specific language governing permissions and
219// limitations under the License.
220// ----------------------------- END-OF-FILE ----------------------------------
221
222/** @} */
223/** @} */
224/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195