ПроблемаНеправильные данные о типе, переданные va_start, происходят когда второй аргумент va_start
макрос имеет один из этих типов данных:
Тип данных, который изменяется при перенесении продвижению параметра по умолчанию.
Например, char
и short
подвергнитесь продвижению int
или unsigned int
и float
подвергается продвижению double
. Типы int
и double
не изменяйтесь при продвижении параметра по умолчанию.
(C только), тип регистра или тип данных объявляются с register
спецификатор.
(Только C++) тип справочных данных.
(Только C++) тип данных, который имеет нетривиального конструктора копии или нетривиального конструктора перемещения.
РискВ функции variadic или функции с переменным количеством аргументов:
void multipleArgumentFunction(int someArg, short rightmostFixedArg, ...) {
va_list myList;
va_start(myList, rightmostFixedArg);
...
va_end(myList);
}
va_start
макрос инициализирует список аргументов переменной так, чтобы дополнительные аргументы к функции variadic после фиксированных параметров могли быть получены в списке. Согласно C11 и C++ 14 Стандартов, если вы используете один из отмеченных типов данных для второго аргумента
va_start
макрос (например,
rightmostFixedArg
в предыдущем примере), поведение не определено.
Если тип данных вовлекает нетривиального конструктора копии, поведение задано реализацией. Например, ли конструктор копии вызывается в вызове va_start
зависит от компилятора.
ФиксацияПри использовании va_start
макрос, попытайтесь использовать типы int
, unsigned int
или double
для самого правого именованного параметра функции variadic. Затем используйте этот параметр в качестве второго аргумента va_start
макрос.
Например, в этом примере, самый правый именованный параметр функции variadic имеет поддерживаемый тип данных int
:
void multipleArgumentFunction(int someArg, int rightmostFixedArg, ...) {
va_list myList;
va_start(myList, rightmostFixedArg);
...
va_end(myList);
}
Чтобы избежать неопределенного и заданного реализацией поведения, минимизируйте использование функций variadic. Используйте средства проверки для MISRA C:2012 Rule 17.1
или MISRA C++:2008 Rule 8-4-1
обнаружить использование функций variadic.
Пример – неправильные типы данных для второго аргумента va_start
#include <string>
#include <cstdarg>
double addVariableNumberOfDoubles(double* weight, short num, ...) {
double sum=0.0;
va_list list;
va_start(list, num);
for(int i=0; i < num; i++) {
sum+=weight[i]*va_arg(list, double);
}
va_end(list);
return sum;
}
double addVariableNumberOfFloats(float* weight, int num, std::string s, ...) {
float sum=0.0;
va_list list;
va_start(list, s);
for(int i=0; i < num; i++) {
sum+=weight[i]*va_arg(list, float);
}
va_end(list);
return sum;
}
В этом примере средство проверки отмечает вызов va_start
\in:
addVariableNumberOfDoubles
потому что аргумент имеет, вводят short
, который подвергается продвижению параметра по умолчанию int
.
addVariableNumberOfFloats
потому что аргумент имеет, вводят std::string
, который имеет нетривиального конструктора копии.
Коррекция — фиксирует тип данных для второго аргумента va_start
Убедитесь что второй аргумент va_start
макрос имеет поддерживаемый тип данных. В следующем откорректированном примере:
В addVariableNumberOfDoubles
, тип данных последнего именованного параметра функции variadic изменяется на int
.
В addVariableNumberOfFloats
, вторые и третьи параметры функции variadic переключаются так, чтобы типом данных последнего именованного параметра был int
.
#include <string>
#include <cstdarg>
double addVariableNumberOfDoubles(double* weight, int num, ...) {
double sum=0.0;
va_list list;
va_start(list, num);
for(int i=0; i < num; i++) {
sum+=weight[i]*va_arg(list, double);
}
va_end(list);
return sum;
}
double addVariableNumberOfFloats(double* weight, std::string s, int num, ...) {
double sum=0.0;
va_list list;
va_start(list, num);
for(int i=0; i < num; i++) {
sum+=weight[i]*va_arg(list, double);
}
va_end(list);
return sum;
}