cupuyc Открыл Америку. Переменному кол-ву параметров сто лет в обед. Не понимаю, чего тут даже обсуждать.
вобщем, случилось то, ради чего я и открывал эту тему. создаю метод: Код (Text): void print_format(const CUtfT &str_format, ...) ... va_start(args, str_format); ... CUtfT *s = va_arg(args, CUtfT*); ... va_end(args); // вызов: print_format(m_str_xml_ver_lang_enc, &m_str_ver_1_0, &m_str_lang, &CUtfT<t_base_char>::get_current_encoding()); передаю дополнительным параметром указатель на CUtfT. после выполнения CUtfT *s = va_arg(args, CUtfT*); в s какой-то бред. проанализировал содержимое стека - там не указатель, а поля структуры CUtfT, хотя я передаю именно указатель. поясните, пожалуйста.
cupuyc А если так? print_format(m_str_xml_ver_lang_enc, (void*)&m_str_ver_1_0, (void*)&m_str_lang, (void*)&CUtfT<t_base_char>::get_current_encoding()); Это конечно же не выход, просто интересно что выдаст твой компиллер. Кстати что за компиллер?
студия девятая. кстати, попробовал сделать простенький пример - там всё пучком. при компиляции 64х кода - тоже всё норм.
Код (Text): class Ca { private: int x, y; public: Ca(int a = 0, int b = 0) { x = a; y = b; } ~Ca() { } int func(int k) { x += k; y -= x; return x + y; } int get_x() const { return x; } int get_y() const { return y; } int format(const Ca &s, ...) { va_list args; va_start(args, s); Ca *p = va_arg(args, Ca*); p->func(20); p = va_arg(args, Ca*); p->func(p->get_x()); p = va_arg(args, Ca*); p->func(p->get_y()); y = p->get_x(); x = p->get_y(); va_end(args); return x; } }; class Cb { private: const Ca m_1, m_2, m_3; Ca m_4; public: Cb() : m_1(2, 3), m_2(3, 4), m_3(0, 0), m_4(2, 2) { } ~Cb() { } void func() { m_4.format(m_1, &m_2, &m_3, &m_3); } }; void Main() { Cb x; x.func(); } вот примерчик - на нём повторяется.
Конечно просто. Для того чтобы добраться до необходимых параметров, va_start берёт адрес передаваемого ей параметра и прибавляет его размер. В случае объекта или указателя это работает. В случае ссылки, берётся адрес не указателя в стеке, а адрес самого объекта. А объект где угодно, но ни как не в стеке. Это препятствие можно преодолеть разве что ассемблерной вставкой.
Имелось ввиду объект не стеке с параметрами. Операция взятия адреса ссылки, возвращает адрес ссылаемого объекта.
на самом деле меня интересует почему компилятор передаёт объект, а не указатель, даже если я явно указываю (void*). вообще говоря, можно было бы сделать и без указателей, типа Ca x = va_arg(args, Ca); но есть 2 проблемы: - будет вызываться конструктор копий - в х64 параметры передаются через указатели, даже если вызвывать m_4.format(m_1, m_2, m_3, m_3); у меня сложилось такое впечатление, что формат, в котором компилятор генерирует передачу параметров мало зависит от моих указаний - так как тогда вообще можно надеяться на va_xxx макросы?
maksim_ Не передаёт он объект, он передаёт ссылку. В С++ получить указатель на ссылку нельзя, можно только на сам объект. И void* нормально работает. Код (Text): будет вызываться конструктор копий Передавай через указатель. Нормально он генерит. Только в случае передачи ссылки, нет тривиального метода получения указателей на нужные параметры.
Я не совсем понимаю где же колдунство? У меня приведённый пример работает. Ссылки/указатели не мешают. Я правда не смог выяснить -- указатели ли передаются, или что: ассемблерный листинг из C++'а получается бешеный и -0s не помогает, плюс сильно "помогает" то, что я до сих пор так и не поинтересовался способами передачи аргументов на x86_64 (хотя gcc вроде пристойно передаёт, наверное это свойства g++). Но это мелочи: код ведь работает.
В случае передачи ссылки, в функцию передаётся адрес объекта. В случае передачи указателем, передаётся значение этого указателя, то есть адрес который в нём хранится. Это два способа сделать одно и то же, разница между которыми существует лишь на уровне кода C++.
r90 И в случае ссылки и указателя, на уровне компилятора передаются указатели. Но чтобы получить указатель на первый необязательный параметр, нужно получить адрес и размер параметра передаваемого va_start. С++ нельзя работать со ссылками как с указателями, и операция взятия адреса у ссылки вернёт не адрес ссылки(передаваемого параметра), а адрес объекта(который хрен знает где).
Я не понимаю зачем работать со ссылкой как с указателем? Или ты исходишь из предположения, что stdarg.h написан без мысли о том, что его будут использовать из c++, и поэтому бездумно берёт адрес от ссылки? Если предположение верно, то это баг в stdarg.h. Надо писать разработчикам, жаловаться -- пускай исправляют. Если им компилятор не позволяет реализовать всё по уму, то одни должны жаловаться разработчикам компилятора, чтобы те реализовали stdarg на уровне компилятора, либо дополнили бы синтаксис C++'а своими фичами позволяющими реализовать stdarg. Скажем в gcc stdarg.h -- это файлик идущий в поставке с компилятором (не с glibc), и внутри него такие надписи: Код (Text): #define va_start(v,l) __builtin_va_start(v,l) #define va_end(v) __builtin_va_end(v) #define va_arg(v,l) __builtin_va_arg(v,l)
r90 Иначе чем через адрес обязательного параметра, добраться до необязательных не возможно. Получение адреса ссылки противоречит самой концепции ссылок и вводить такое в стандарт вряд ли станут. Может и можно сделать черезжопное расширение, но не факт что его поддержат другие компиляторы, а раз так, то получаем непереносимую фичу. По-этому с этим нужно просто смириться.
ага, дошло. какой выход? юзать первым параметром указатель вместо ссылки? глянул в MFC - там первым параметром передаётся не CString, а PCXSTR, что, вообще говоря, глупо. если мне одновременно нужно юзать и utf и ascii строки... если это внутри шаблона... Код (Text): template <typename t> void func() { CStringT<t> s; s.format(/* х.з. */) }
Почему глупо передавать указатель на форматную строку? Ведь от неё не требуется какой-то изощрённой кодировки.