Начиная с C99, спецификация va_arg
читается частично
Если [тип, переданный va_arg
в качестве аргумента], несовместим с типом фактического следующего аргумента (как продвигается в соответствии с продвижением аргументов по умолчанию), поведение не определено, за исключением следующих случаев:
- один тип является целочисленным типом со знаком, другой тип является соответствующим целочисленным типом без знака, и значение представимо в обоих типах;
- один тип является указателем на void, а другой - указателем на тип символа.
Вторая точка маркера означает, что для любой переменной функции, которая использует va_arg
для доступа к своим аргументам, вызов вида
variadic_function("a", "b", "c", (void *)0);
будет действовать всякий раз, когда
variadic_function("a", "b", "c", (char *)0);
было бы.
К сожалению, есть одна загвоздка: я не могу найти никаких требований для переменной стандартной библиотеки функций 1 , чтобы [вести себя так, как будто они] получают доступ к своим аргументам, делая серия звонков на va_arg
. Вы, наверное, думаете, ну, как еще они собираются это сделать? На практике это va_arg
или рукописный язык ассемблера, и, возможно, комитет не хотел требовать, чтобы рукописный язык ассемблера был идеально эквивалентом, но я не стал бы беспокоиться об этом.
Так что книга, которую вы цитируете, технически неверна. Впрочем, я бы все равно написал
execl(prog, arg, (char *) NULL);
если я собирался использовать NULL в первую очередь (я обычно предпочитаю использовать 0
в качестве константы нулевого указателя), потому что вы не должны писать код, который полагается на расширение NULL до ((void *)0)
и
execl(prog, arg, 0);
, безусловно, неверно. Например, execl
не получит нулевой указатель от этого 0
на любом ABI, где int
- 32 бита, char *
- 64 бита, а значения int
не расширены до нуля или знака до 64 биты, когда передаются как часть списка аргументов переменной.
1 execl
не является частью стандарта C , но является частью стандарта POSIX, и любая система, обеспечивающая execl
, в первую очередь, вероятно, соответствует по крайней мере с подмножеством POSIX. Можно предположить, что все из пункта 7.1.4 стандарта C применимо и к функциям, указанным в POSIX.