С++ для начинающих. Функции с переменным числом параметров

Иногда у начинающих возникает вопрос про использование многоточия в языке С++.
  • Многоточие можно использовать тогда, когда по каким-то причинам предполагается создать функцию с неизвестным заранее числом идущих в функцию аргументов. В объявлении и определении такой функции переменное число аргументов задается многоточием, обязательно в конце списка формальных параметров.
  • Многоточие иногда используют, но в зависимости от компиляторов, один из старых способов может совсем не давать желаемого эффекта. До С++11 рекомендуется использовать только вариант с stdarg , а варианты, показанные внизу страницы, рекомендуется не использовать вообще.
На заметку:

  • Для того, чтобы получить доступ ко всем параметрам, принимающих значения аргументов, заходящих в функцию, обязательно знать имя и тип хотя бы одного параметра.
В функцию можно отдавать произвольное число аргументов и не зависеть от типов аргументов. Чтобы функция могла обработать подобный подарок, имеет смысл использовать специальный набор макроопределений, которые становятся доступными при включении в программу заголовочного файла stdarg.h. Эти макроопределения обеспечивают стандартный (независящий от реализации) способ доступа к спискам параметров переменной длины.
Код С++ функции с произвольным числом параметров переменной длины (C++ 3.1)
До С++11 рекомендуется использовать stdarg

  • Cпециальный тип va_list используется для представления списков параметров неизвестной длины и состава.
  • va_start вызывается непосредственно перед началом работы с неименованными параметрами.
  • ар инициализируется указателем на последний именованный параметр в списке с переменным числом параметров — параметр lastarg.

    Здесь подпараметр является условным обозначением и относится к макрокомандам, а не функциям.
  • После вызова макроопределения va_start, каждый вызов va_arg возвращает значение заказанного типа type себе. Надо заранее указать тип желаемого параметра. В некоторых реализациях с макроопределением va_arg запрещено использовать типы char, unsigned char, float. Даже в макроопределениях, предназначенных для стандартизации языка (речь идет не о Borland C++ 3.1, а о более новых), многое зависит от реализации.
  • Работа со списком параметров завершается вызовом макроопределения void va_end(ap); Это макроопределение обеспечивает корректный возврат из функции и вызывается перед выходом из функции.
Код С++ Функции с произвольным числом параметров переменной длины:

===================================
Код С++. НЕ РЕКОМЕНДУЕТСЯ. Может работать и правильно, и неправильно: зависит от компилятора и от компьютера, на котором выполняется программа.

Этот код не только не рекомендуется, но рекомендуется забыть навсегда, что так можно было когда-то. Хотя некоторые функции в языке С работают именно на этом принципе, в языке С++ для работы с переменным числом параметров, во всех компиляторах, не поддерживающих С++11, нужно использовать только макрос stdarg.
Хотя вы можете встречать следы истории в книгах и на некоторых сайтах, где может приводиться пример суммы:

Несмотря на то, что этот код может сработать у вас как и ожидается, если вам повезёт, то достаточно использовать double вместо int и всё пойдёт насмарку. Если не очень повезёт, то сработает, как ожидалось. Но это полностью платформозависимый код. Ужасный код.



Все комментарии на сайте проверяются, поэтому ваш комментарий может появиться не сразу. Для вставки кода в комментарий используйте теги: [php]ВАШ_КОД[/php]

20 комментариев: С++ для начинающих. Функции с переменным числом параметров

  • Марк говорит:

    Чётко, чётко




    0



    0
  • Аноним говорит:

    😆




    0



    0
  • 1 говорит:

    😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆 😆




    0



    0
  • ttkm говорит:

    target pattern contains no «%» stop
    выскакивает эта ошибка и не работает задача, подскажите плиз как этого миновать, плиз 😥




    0



    0
  • Вовка говорит:

    как мне подставить формулу

    S = a1 * a2 + a2 * a3 + a3 * a4 + . . .;

    допусутим для 5 переменных
    s + = (*p)*(*p) — не катит((




    0



    0
    • admin говорит:

      Это обязательно через такую функцию делать?
      Если я знаю ответ, то завтра отвечу. Если не знаю ответа, то завтра скажу, что не знаю.

      Могу только предположить, что в месте вызова функции, прописывать можно что-то типа

      ну и смотреть пример с суммой.
      но не могу сказать, что это вообще работать будет, проверить не могу.

      Не в описании функции, а там, откуда ее вызываем.




      0



      0
      • admin говорит:

        или же

        как-то так (проверить не могу)




        0



        0
    • admin говорит:

      проверил

      но работает это в Borland C++ 3.1, в Linux же, например, весь этот алгоритм сам по себе ошибка. Правильнее было бы использовать код подобно коду из последнего примера.




      0



      0
  • Александр говорит:

    У меня вопрос — и он на праздный вот такой — 😈 👿 — сам я знаток языка, использую эти вот штуки. но вот теперь на си++ обнаружил что обязательного параметра может и не быть — а это тот самый случай который мне нужен. у меня конструктор, и сразу можно подцепить к обьекту связанные с ним штуки(ну это обьект со штуками такой, вы меня понимаете) т.е. передаются указатели, замыкает ноль — конец списка.и синтаксичестки правильно и компилятор разделяет мою точку зрения, да вот незадача то 🙁 🙁 👿 😡 😥 😥 😥 😥 раз нет первого параметра — ЧЕМ мне бедолаге горемычному инициализировать указатель тот волшебный??? Липман молчит ка рыба об лёд, а у Интернета я только начал интересоваться и забрёл на ваш сайт.




    0



    0
    • admin говорит:

      Сам я совсем не знаток языка и не использую такие штуки, поэтому мне немного забавна ситуация с обращением ко мне за советом от знатока.
      Если вы знаток, то должны знать, что на компилятор надеяться глупо. Он многое допускает, но не все, что он допускает будет впоследствии работать и не все допустимые конструкции получится использовать.

      Если бы я встретил способ, о котором вы спрашиваете, то я бы описал его еще до вашего вопроса.
      Но способа такого, насколько я знаю, нет.

      Должна быть точка отсчета. Точка отсчета узнается по первому параметру.
      Грубо говоря, когда компилятор работает, чтобы запустить программу, для каждой найденной функции он выделяет какую-то область памяти, а также для каждой переменной по функции тоже выделяется память. Первый такой адрес по переменной для функции как раз и будет точкой отсчета.

      Зачем компилятор допускает что-то типа void myfunc(…) я понятия не имею.




      0



      0
      • Максим говорит:

        в си++ можно переопределять функции для разных списков типов входных данных(включая пустой), т.е. можно описать функцию с одним именем, но принимающую разные типы параметры и в зависимости от того от чего она будет вызываться в коде будет вызвана нужная.




        0



        0
        • admin говорит:

          если это имеет отношение к функциям вида myfunc(…), я бы очень хотел увидеть пример. это сложно найти.
          ===================
          по поводу претензий и сегменташин фолт — я всего лишь заимствовал коды из других источников и собрал их сюда. Так как они написаны в разных книгах и на разных форумах, авторов я указывать не стал. (я не знаю истинного автора) но исправлю




          0



          0
          • Максим говорит:

            этот прототип(как и любой другой) говорит транслятору только то, что для функции (будь она от void или с переменным списком параметров) к моменту раскрытия ссылок на тело, это тело будет где-то существовать и он может смело продолжать формировать объектник.




            0



            0
            • admin говорит:

              а поконкретнее? я ж не компилятор
              прототип прототипом, я спрашивал не про прототип, а про функцию с телом.

              вопрос, который мне задали, куда вы далее вписали и свой комментарий с пояснением — это вопрос о таких функциях. Зачем допускается возможность?




              0



              0
          • Максим говорит:

            не допускается, компилятор выдаст ошибку.
            прототип возможно в некоторых компиляторах и пройдёт.




            0



            0
  • Максим говорит:

    а во большинстве листингах ошибки, функция контролирует конец списка параметров по нулю в конце, а вызывая функцию этот самый ноль в конец не добавляете, в итоге привет сегменташин фолт.
    также, шагая по списку параметров нельзя просто прибавлять размер параметра, так как некоторые типы при засовывании в стек расширяются, например на 32битных системах обычно при засовывании short и char расширяются до int т.е. записываются в стек 4 байта. так что для чтения параметров нужно пользоваться макросом va_arg(list,type), а не прибавлять размер предыдущего считанного параметра.




    0



    0

Добавить комментарий

Ваш e-mail не будет опубликован.

Поиск

 
     

Случайная книга в электронном формате

Яндекс.Метрика
НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

Демотиватор программирование на языке ада

Выражаю свою признательность

  • Максиму очень признателен за указание на мои ошибки и неточности.
  • Sergio ===> за оказание помощи в исправлении моих ошибок
  • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок