В каких случаях следует использовать список va
Я сделал небольшую библиотеку C, которая реализует алгоритмы теории графов и связывает их для использования в Python.
Я отправить его другу, чтобы проверить его, и он сказал мне, что va_list
является "опасным" и не должен использоваться в такого рода проекте.
Итак, вопрос. В каких случаях va_list
следует использовать?
4 ответов
основная проблема, которую я вижу, заключается в том, что нет никакой гарантии, что вы действительно получили количество аргументов, которые вы ожидали, и нет способа проверить это. Это делает ошибки необнаруживаемыми, а необнаруживаемые ошибки, очевидно,наиболее опасны. va_arg
также не является типобезопасным, что означает, что если вы передадите double
и unsigned long long
, вы получите мусор вместо красивого целого числа и не сможете обнаружить его во время компиляции. (Это становится гораздо больше беспорядка, когда типы даже не имеют одинакового размера).
В зависимости от данных, с которыми вы имеете дело, это может быть более или менее проблемой. Если вы передаете указатели, почти мгновенно становится фатальным опустить аргумент, потому что ваша функция будет извлекать мусор вместо этого, и это мог бы (если планеты правильно выровнены) стать уязвимостью.
Если вы передаете" регулярные " числовые данные, это зависит от того, является ли функция критической. В некоторых случаях вы можете легко обнаружить ошибку глядя на выход функции, и в некоторых практических случаях это действительно не такая большая проблема, если функция терпит неудачу.
все это вращается, если вы боитесь забыть аргументы сами, на самом деле.
C++11 имеет функцию variadic template, которая позволяет безопасно обрабатывать произвольное количество параметров. Если шаг от C до c++ не слишком болит, вы можете изучить его.
В C++11, va_list
никогда не следует использовать, так как он обеспечивает лучшую альтернативу под названием шаблон variadic, который typesafe тогда как va_list
нет.
в C вы можете использовать va_list
когда вам нужна variadic функция, но будьте осторожны, так как она не является typesafe.
и да, ваш друг прав:va_list
is опасно. Избегайте этого как можно больше.
в C и C++03, стандартная функция библиотеки printf
реализуется с помощью va_list
, именно поэтому программисты C++03 обычно избегают использовать это, так как это не безопасно.
но в вариативную typesafe printf
может быть реализован в C++11, как: (взято из wiki)
void printf(const char *s)
{
while (*s) {
if (*s == '%' && *(++s) != '%')
throw std::runtime_error("invalid format string: missing arguments");
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char *s, T value, Args... args)
{
while (*s) {
if (*s == '%' && *(++s) != '%') {
std::cout << value;
++s;
printf(s, args...);
return;
}
std::cout << *s++;
}
throw std::logic_error("extra arguments provided to printf");
}
va_list
имеет некоторые неудачи, связанные с недооценкой аргументов функции:
- при вызове такой функции компилятор не знает, какие типы
аргументы ожидаются, поэтому стандарт накладывает некоторые " обычные
преобразование " перед передачей аргументов в функцию. Е. Г
целые числа, которые уже, чем
int
поощряются, всеfloat
есть повышен доdouble
. В каком-то пограничном случае ты не получил того, что получил. хотела назвать функция. - в вызываемой функции вы сообщаете компилятору, какой тип аргумента вы ожидаете и сколько их. Нет никакой гарантии, что звонящий получит это право.
если вы передадите количество аргументов в любом случае, и они имеют тот же известный тип, вы можете просто передать их с временным массивом, написанным для C99:
void add_vertices(graph G, vertex v, size_t n, vertex neigh[n]);
вы бы назвали это чем-то вроде этого
add_vertices(G, v, nv, (vertex []){ 3, 5, 6, 7 });
если это вызывающее соглашение выглядит слишком уродливым для вы, вы могли бы обернуть его в макрос
#define ADD_VERTICES(G, V, NV, ... ) add_vertices((G), (V), (NV), (vertex [NV]){ __VA_ARG__ })
ADD_VERTICES(G, v, nv, 3, 5, 6, 7);
на ...
указывает аналогичную концепцию для макросов. Но результат намного безопаснее, так как компилятор может выполнить проверку типа, и это не откладывается до выполнения.Если вы хотите реализовать функцию в C с переменным количеством аргументов, вы можете использовать va_list. Например, printf использует va_list. Не знаю, почему это может быть опасно.