Многоточие NULL, nullptr и неопределенное поведение - PullRequest
0 голосов
/ 04 февраля 2019

У меня есть функция, принимающая переменную, и NULL завершает список аргументов указателя, используя elipsis.Я знаю о списках аргументов шаблона переменной длины.Речь идет об унаследованном коде.Приведут ли следующие два вызова к неопределенному поведению, потому что терминатор интерпретируется как Serializable * va_arg?Каковы различия между двумя вызовами?

void serialize(Serializable* first, ...) {
    va_list vl;

    va_start(vl, first);

    while(1)
    {
        Serializable* arg = va_arg(vl, Serializable*);

        if(arg == NULL)
            break;

        /* serialize arg here */
    }
}

serialize(obj1, obj2, obj3, NULL);
serialize(obj1, obj2, obj3, nullptr);

1 Ответ

0 голосов
/ 04 февраля 2019

Нет, я так не думаю.

Цитирование cppreference.com на va_arg:

Если тип следующего аргумента вap (после повышения по службе) несовместимо с T, поведение не определено, кроме случаев, когда:

  • один тип является целочисленным типом со знаком, другой тип является соответствующим целочисленным типом без знака, изначение представимо в обоих типах;или
  • один тип является указателем на void, а другой - указателем на тип символов (char, signed char или unsigned char).

(Это очень близко соответствует фактической формулировке C11; помните, va_arg определяется C, а не C ++.)

Теперь определение "совместимых типов" в C11 суммируется с помощью другой cppreference, который учит нас, что для того, чтобы ваш NULL имел тип, совместимый с Serializable*, тип pointee NULL должен быть совместим с Serializable.

Теперь, NULL имеет определяемый реализацией тип , поэтому вы не можете знать, что это такое, но он определенно не будет совместимым с Serializable, если только это не псевдоним типа для voidили int и вам повезет.

С nullptr вы получите void*, но затем снова см. выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...