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

Сайт не является учебником по программированию. Это только небольшой авторский сборник информации в помощь начинающим программистам.

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

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

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

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

  Эти макроопределения обеспечивают стандартный (независящий от реализации) способ доступа к спискам параметров переменной длины.

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

      • Код С++ Функции с произвольным числом параметров переменной длины
      • Visual Studio Express 2012

      ===================================
      Код С++. НЕ РЕКОМЕНДУЕТСЯ. просто может работать. А может работать неправильно.

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

        Должен возникнуть вопрос как же получить доступ к каждому из этих параметров. Для того, чтоб хорошо понять то что будет написано, требуется знание указателей. Чтобы иметь доступ к каждому из параметров, нужно знать адрес первого параметра, а чтобы взять этот адрес, как раз и требуется указатель

      Код С++. НЕ РЕКОМЕНДУЕТСЯ. просто может работать. А может работать неправильно.

        Что можно увидеть? Первым делом внутри функции происходят взятие адреса первого параметра, при этом тип указателя должен совпадать с типом этого параметра. Дальше идет простой перебор всех параметров с помощью цикла.

      Таким же образом можно привести классический пример суммирования элементов

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

        Даже если типы передаваемых параметров будут различны, то компилятор не выдаст ошибки, но ошибки не выведется только потому что если компилятор видит эти три точки на месте параметров, то он отключает проверку типов. На самом деле легко увидеть эффект небезопасности работы с функцией, в которой указано, что будет более одного параметра, если первый параметр объявить например как int, (соответственно указатель на первый параметр как int), а во время передачи в функцию написать число с точкой (например 1.0 запустить и потом 11.0 и запустить). Т.е. если требуется передать параметры других типов, то их все нужно дописать перед списком предполагаемых неизвестных.
      Например void MyFunc(float x, char S[],int n,…), после чего с первыми работать в обычной манере, а с теми что после n с помощью указателя на int и, соответственно, передавать туда параметры с тем же типом, что и у этого n (Исходя из логики того, что тип указателя должен совпадать с типом объекта на адрес которого указатель ссылается).

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

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

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

    Чётко, чётко

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

    😆

  • 1 говорит:

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

  • ttkm говорит:

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

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

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

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

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

    • admin говорит:

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

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

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

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

      • admin говорит:

        или же

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

    • admin говорит:

      проверил

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

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

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

    • admin говорит:

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

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

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

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

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

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

        • admin говорит:

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

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

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

            • admin говорит:

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

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

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

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

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

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

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

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

Поиск

 
     

Яндекс.Метрика

НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

Кошки стали умнее людей — не регистрируются вконтакте, не заводят твиттер

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

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