ПроблемаНеверные данные типа, переданные в 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);
} va_start макрос инициализирует список переменных аргументов, так что дополнительные аргументы для переменной функции после фиксированных параметров могут быть зафиксированы в списке. В соответствии со стандартами 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;
}