Ограничение для параметров регистров или параметров функций, вероятно, выглядит примерно так:
регистр
. va_start ()
и / или va_arg ()
были реализованы путем добавления некоторой фиксированной суммы к адресу paramN
и указатели функций были больше, чем указатели объектов, расчет приведет к неправильному адресу для объекта , который возвращает va_arg ()
. Может показаться, что это не лучший способ реализовать эти макросы, но могут быть платформы, которые имеют (или даже нуждаются) в этом типе реализации. Я не могу придумать, в чем проблема может заключаться в предотвращении разрешения параметров массива , но PJ Plauger говорит об этом в своей книге «Стандартная библиотека C»:
Некоторые ограничения, наложенные на макросы, определенные в
, кажутся излишне жесткими. Для некоторых реализаций они есть. Однако каждый был представлен чтобы удовлетворить потребности хотя бы одной серьезной реализации C.
И я полагаю, что мало кто знает о тонкостях библиотеки C больше, чем Plauger. Я надеюсь, что кто-то сможет ответить на этот конкретный вопрос на реальном примере; Я думаю, это будет интересная мелочь.
Новая информация:
"Обоснование международного стандарта - Языки программирования - C" говорит о va_start ()
:
аргумент parmN
дляva_start
был предназначен для помощи разработчикам, пишущим определение соответствующего макросаva_start
полностью на C, даже с использованием компиляторов до C89 (например, путем взятия адреса параметра). Ограничения на объявление параметраparmN
вытекают из намерения разрешить этот вид реализации, поскольку применение оператора & к имени параметра может не дать желаемого результата, если объявление параметра не соответствует этим ограничениям. .
Не то, чтобы это помогло мне с ограничением параметров массива.
Это не неопределенно. Имейте в виду, что когда параметр объявлен как int paramN []
, фактический тип параметра все равно немедленно изменится на int * paramN
(что видно в C ++, например, если вы примените typeid
к paramN
).
Я должен признать, что я не уверен, для чего вообще нужен этот бит в спецификации, учитывая, что у вас не может быть параметров функции или массива типы в первую очередь (поскольку они будут распадаться по указателю).
I found another relevant quote, from Dinkumware.
The last parameter must not have register storage class, and it must have a type that is not changed by the translator. It cannot have:
* an array type * a function type * type float * any integer type that changes when promoted * a reference type [C++ only]
So apparently, the problem is precisely that the parameter gets passed in a way different from how it is declared. Interestingly enough, they also ban float and short, even though those should be supported by the standard.
As a hypothesis, it could be that some compilers have problems doing sizeof
correctly on such parameters. E.g. it might be that, for
int f(int x[10])
{
return sizeof(x);
}
some (buggy) compiler will return 10*sizeof(int)
, thus breaking the va_start
implementation.
Я могу только догадываться, что ограничение регистр
предназначено для упрощения реализации библиотеки / компилятора - это устраняет особый случай, о котором им следует беспокоиться.
Но я понятия не имею об ограничении массива / функции. Если бы это было только в стандарте C ++, я бы рискнул предположить, что существует некий неясный сценарий сопоставления шаблонов, в котором разница между параметром типа T []
и типа T *
имеет значение, правильная обработка которого усложнила бы va_start
и т. д. Но поскольку этот пункт также присутствует в стандарте C, очевидно, что такое объяснение исключено.
Мой вывод: упущение в стандартах. Возможный сценарий: некоторый предстандартный компилятор C реализовал параметры типа T []
и T *
по-разному, и представитель этого компилятора в комитете по стандартам C добавил к стандарту вышеуказанные ограничения; этот компилятор позже устарел, но никто не считал, что ограничения достаточно убедительны, чтобы обновить стандарт.