BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsla_scanf

Macros

#define BSLA_SCANF(FMTIDX, STARTIDX)
 

Detailed Description

Outline

Purpose

Provide a macro for checking scanf-style format strings.

Macros

See also
bsla_annotations

Description

This component provides a preprocessor macro that indicates that one of the arguments to a function is a scanf-style format string, and that the arguments starting at a certain index are to be checked for compatibility with that format string.

Macro Reference

BSLA_SCANF(FMTIDX, STARTIDX): This annotation instructs the compiler to perform additional checks on so-annotated functions that take scanf-style arguments, which should be type-checked against a format string.

BSLA_SCANF_IS_ACTIVE: The macro BSLA_SCANF_IS_ACTIVE is defined if BSLA_SCANF expands to something with the desired effect; otherwise BSLA_SCANF_IS_ACTIVE is not defined and BSLA_SCANF expands to nothing.

Usage

This section illustrates intended use of this component.

Example 1: Populate a Sequence of ints and floats with Random Numbers

Suppose we want to have a function that will populate a list of ints and floats with random numbers in the range [ 0 .. 100 ).

First, we define our function:

int populateValues(const char *format, ...) BSLA_SCANF(1, 2);
// Use 'rand' to populate 'int's and 'float's, passed by pointer after
// the specified 'format', which will specify the types of the
// variables passed. Return the number of variables populated, or -1
// if the format string is invalid.
int populateValues(const char *format, ...)
{
int ret = 0;
va_list ap;
va_start(ap, format);
for (const char *pc = format; *pc; ++pc) {
if ('%' != *pc) {
continue;
}
const char c = *++pc;
if ('%' == c) {
continue;
}
else if ('d' == c) {
* va_arg(ap, int *) = static_cast<unsigned>(rand()) % 100;
}
else if ('f' == c || 'e' == c || 'g' == c) {
const int characteristic = static_cast<unsigned>(rand()) % 100;
const int mantissa = static_cast<unsigned>(rand()) % 1000;
* va_arg(ap, float *) = static_cast<float>(characteristic +
mantissa / 1000.0);
}
else {
// Unrecognized character. Return a negative value.
ret = -1;
break;
}
++ret;
}
va_end(ap);
return ret;
}

Then, in main, we call populateValues properly:

float ff[3] = { 0, 0, 0 };
int ii[3] = { 0, 0, 0 };
int numVars = populateValues("%d %g %g %d %d %g",
&ii[0], &ff[0], &ff[1], &ii[1], &ii[2], &ff[2]);
assert(6 == numVars);
for (int jj = 0; jj < 3; ++jj) {
assert(0 <= ii[jj]);
assert(0 <= ff[jj]);
assert( ii[jj] < 100);
assert( ff[jj] < 100);
}
printf("%d %g %g %d %d %g\n",
ii[0], ff[0], ff[1], ii[1], ii[2], ff[2]);

Next, we observe that there are no compiler warnings and a reasonable set of random numbers are output:

83 86.777 15.793 35 86 92.649

Now, we make a call where the arguments don't match the format string:

numVars = populateValues("%d %g", &ff[0], &ii[0]);

Finally, we observe the following compiler warnings with clang:

.../bsla_scanf.t.cpp:351:43: warning: format specifies type 'int *' but the
argument has type 'float *' [-Wformat]
numVars = populateValues("%d %g", &ff[0], &ii[0]);
~~ ^~~~~~
%f
.../bsla_scanf.t.cpp:351:51: warning: format specifies type 'float *' but
the argument has type 'int *' [-Wformat]
numVars = populateValues("%d %g", &ff[0], &ii[0]);
~~ ^~~~~~
%d

Macro Definition Documentation

◆ BSLA_SCANF

#define BSLA_SCANF (   FMTIDX,
  STARTIDX 
)