ПроблемаНеправильные данные типа, переданные в va_start, возникают, когда второй аргумент va_start
макрос имеет один из следующих типов данных:
Тип данных, который изменяется при продвижении аргумента по умолчанию.
Для образца, char
и short
пройти повышение в int
или unsigned int
и float
проходит повышение до double
. Типы int
и double
не изменяйте при повышении аргумента по умолчанию.
(Только для C) Тип регистра или тип данных, объявленный с register
квалификатор.
(Только для C++) Ссылочный тип данных.
(Только для C++) Тип данных, который имеет нетривиальный конструктор копирования или нетривиальный конструктор перемещения.
РискВ вариадной функции или функции с переменным количеством аргументов:
void multipleArgumentFunction(int someArg, short rightmostFixedArg, ...) {
va_list myList;
va_start(myList, rightmostFixedArg);
...
va_end(myList);
}
The
va_start
macro инициализирует список аргументов переменной, чтобы дополнительные аргументы в переменную функцию после фиксированных параметров могли быть захвачены в списке. Согласно стандартам C11 и C++ 14, если вы используете один из отмеченных типов данных для второго аргумента
va_start
макрос (для образца,
rightmostFixedArg
в предыдущем примере), поведение не определено.
Если тип данных включает нетривиальный конструктор копирования, поведение определяется реализацией. Для образца, вызывается ли конструктор копирования в вызове va_start
зависит от компилятора.
ЗафиксироватьПри использовании va_start
макрос, попробуйте использовать типы int
, unsigned int
или double
для крайнего правого именованного параметра вариадной функции. Затем используйте этот параметр как второй аргумент va_start
макрос.
Например, в этом примере самый правый именованный параметр вариадной функции имеет поддерживаемый тип данных int
:
void multipleArgumentFunction(int someArg, int rightmostFixedArg, ...) {
va_list myList;
va_start(myList, rightmostFixedArg);
...
va_end(myList);
}
Чтобы избежать неопределенного и определяемого реализацией поведения, минимизируйте использование вариадных функций. Используйте шашки для MISRA C:2012 Rule 17.1
или MISRA C++:2008 Rule 8-4-1
для обнаружения использования вариадных функций.
Пример - Неправильные типы данных для второго аргумента 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
в:
addVariableNumberOfDoubles
поскольку аргумент имеет тип short
, который по умолчанию повышает аргумент до int
.
addVariableNumberOfFloats
поскольку аргумент имеет тип std::string
, который имеет нетривиальный конструктор копирования.
Коррекция - Исправление типа данных для второго аргумента va_start
Убедитесь, что второй аргумент va_start
макрос имеет поддерживаемый тип данных. В следующем исправленном примере:
В addVariableNumberOfDoubles
тип данных последнего именованного параметра вариадной функции изменяется на int
.
В addVariableNumberOfFloats
второй и третий параметры вариадной функции переключаются так, что тип данных последнего именованного параметра 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;
}