#c #variadic-functions
#c #variadic-функции
Вопрос:
Я пытаюсь заткнуть дыру в своих знаниях. Почему переменные функции требуют как минимум двух аргументов? В основном из main
функции C, имеющей argc
в качестве аргумента количество, а затем argv
в виде массива массивов символов? Кроме того, в Cocoa Objective-C есть NSString
методы, которые требуют форматирования в качестве первого аргумента, а затем массива аргументов ( [NSString stringWithFormat:@"%@", foo]
) . Почему невозможно создать переменную функцию, принимающую только список аргументов?
Ответ №1:
материал argc / argv на самом деле не является переменным.
Переменные функции (такие как printf()
) используют аргументы, помещенные в стек, и требуют не как минимум 2 аргумента, а 1.
У вас есть void foo(char const * fmt, ...)
и обычно fmt
дает представление о количестве аргументов. Это минимум 1 аргумент (fmt).
Ответ №2:
C имеет очень ограниченные возможности отражения, поэтому у вас должен быть какой-то способ указать, что содержат переменные аргументы — либо указать количество аргументов, либо их тип (или оба), и это логика наличия еще одного параметра. Это требуется стандартом ISO C, поэтому вы не можете его пропустить. Если вы чувствуете, что вам не нужны никакие дополнительные параметры, потому что количество и тип аргументов всегда постоянны, тогда в первую очередь нет необходимости в переменных аргументах.
Конечно, вы могли бы разработать другие способы кодирования информации о числе / типе внутри переменных аргументов, таких как контрольное значение. Если вы хотите это сделать, вы можете просто указать фиктивное значение для первого аргумента и не использовать его в теле метода.
И просто чтобы быть педантичным в отношении вашего названия, переменные функции требуют только одного аргумента (не двух). Вполне допустимо вызывать переменную функцию без предоставления каких-либо необязательных аргументов:
printf("Hello world");
Комментарии:
1. Хм, если вы все равно используете sentinel , не могли бы вы просто сделать первый аргумент того же типа, что и sentinel, и организовать цикл так, чтобы первое значение параметра не было получено из va_list ? Это не похоже на то, что вызов без аргументов на самом деле будет действительным в первую очередь, поскольку вам всегда нужен sentinel в конце в любом случае.
Ответ №3:
Я думаю, что причина в следующем: в макросе va_start(list, param);
вы указываете последний фиксированный аргумент — он необходим для определения адреса начала списка переменных аргументов в стеке.
Ответ №4:
Как бы вы тогда узнали, предоставил ли пользователь какие-либо аргументы?
Должна быть какая-то информация, указывающая на это, и C вообще не был разработан для скрытой обработки данных. Итак, все, что вам нужно, заставляет вас передавать явно.
Ответ №5:
Я уверен, что если бы вы действительно хотели, вы могли бы попытаться применить некоторую схему, при которой переменная функция принимает только определенный тип параметра (например, список целых чисел), а затем вы заполняете некоторую глобальную переменную, указывающую, сколько целых чисел вы передали.
Ваши два примера не являются вариационными функциями. Это функции с двумя аргументами, но они также подчеркивают аналогичную проблему. Как вы можете узнать размер массива C без дополнительной информации? Вы можете либо передать размер массива, либо описать схему с некоторым контрольным значением, обозначающим конец массива (т. Е. » для строки C).
Как в случае переменных, так и в случае массива у вас одна и та же проблема: как вы можете узнать, к какому объему данных у вас есть законный доступ? Если вы не знаете этого в случае массива, вы выйдете за рамки. Если вы не знаете этого в случае переменных, вы будете вызывать va_arg слишком много раз или с неправильным типом.
Чтобы изменить вопрос, как бы вы могли реализовать функцию, принимающую переменное количество аргументов, не передавая дополнительную информацию?