Не уверен, что это баг.
Для инициализации va_list нужен адрес последнего фиксированного параметра на стеке, у вас же count передается по ссылке (реально в стеке находится указатель на count), и, когда мы берем адрес count, мы получаем не адрес на стеке, а адрес где размещен count — может на стеке вызывающей функции, может динамической памяти, или где там этот count определен. Имхо, при взятии адреса от ссылки возвращается адрес объекта, а не адрес ссылки — по моим ощущениям, это ближе к стандарту, хотя могу ошибаться. Gcc, возможно, просто "догадался", что вы имели ввиду, но имхо он не прав.
Здравствуйте, Marty, Вы писали:
M>Не уверен, что это баг. M>Для инициализации va_list нужен адрес последнего фиксированного параметра на стеке, у вас же count передается по ссылке (реально в стеке находится указатель на count), и, когда мы берем адрес count, мы получаем не адрес на стеке, а адрес где размещен count — может на стеке вызывающей функции, может динамической памяти, или где там этот count определен. Имхо, при взятии адреса от ссылки возвращается адрес объекта, а не адрес ссылки — по моим ощущениям, это ближе к стандарту, хотя могу ошибаться. Gcc, возможно, просто "догадался", что вы имели ввиду, но имхо он не прав.
Я где-то так и думал. Нужно будет почитать про устройство ссылок. Спасибо.
Здравствуйте, SaZ, Вы писали:
SaZ>Следующий код не работает в msvc 2010, но работает в gcc: SaZ>(Если убрать ссылку, то всё работает)
SaZ>А как должно быть на самом деле?
Это UB, поэтому "на самом деле" может происходить что угодно.
Marty:
M>Gcc, возможно, просто "догадался", что вы имели ввиду, но имхо он не прав.
А в чём он, собственно, не прав? Неопределённое поведение вполне может совпасть с желаемым. То, что поведение тут неопределённое, явным образом прописано в C++11 — 18.10/3:
The restrictions that ISO C places on the second parameter to the va_start() macro in header <stdarg.h> are different in this International Standard. The parameter parmN is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the ...). [Footnote: Note that va_start is required to work as specified even if unary operator& is overloaded for the type of parmN.] If the parameter parmN is declared with a function, array, or reference type, or with a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined.
Здравствуйте, Marty, Вы писали:
M>Не уверен, что это баг. M>Для инициализации va_list нужен адрес последнего фиксированного параметра на стеке, у вас же count передается по ссылке (реально в стеке находится указатель на count), и, когда мы берем адрес count, мы получаем не адрес на стеке, а адрес где размещен count — может на стеке вызывающей функции, может динамической памяти, или где там этот count определен. Имхо, при взятии адреса от ссылки возвращается адрес объекта, а не адрес ссылки — по моим ощущениям, это ближе к стандарту, хотя могу ошибаться. Gcc, возможно, просто "догадался", что вы имели ввиду, но имхо он не прав.
какой-то бред. Полное не понимание, что передается и как.
Если верить Вашей логике, то и *Count нельзя использовать (т.к. там такой же адрес как и &Count), а это не так.
Здесь имеет место быть просто ошибка MS (довольно старая) и делать какие-либо теоретические выкладки — глупо
Здравствуйте, Сергей Мухин, Вы писали:
M>>Не уверен, что это баг. M>>Для инициализации va_list нужен адрес последнего фиксированного параметра на стеке, у вас же count передается по ссылке (реально в стеке находится указатель на count), и, когда мы берем адрес count, мы получаем не адрес на стеке, а адрес где размещен count — может на стеке вызывающей функции, может динамической памяти, или где там этот count определен. Имхо, при взятии адреса от ссылки возвращается адрес объекта, а не адрес ссылки — по моим ощущениям, это ближе к стандарту, хотя могу ошибаться. Gcc, возможно, просто "догадался", что вы имели ввиду, но имхо он не прав.
СМ>какой-то бред. Полное не понимание, что передается и как.
Ну я и писал имхо. СМ>Если верить Вашей логике, то и *Count нельзя использовать (т.к. там такой же адрес как и &Count), а это не так.
Нет, не так. При взятии адреса указателя будет взят именно адрес указателя, а не адрес адресуемого этим указателем объекта. Можно попробовать — создать 100500 различно вложенных функций, в которые передавать ссылку и брать от нее адрес — думаю, результат будет везде одинаков. И второй вариант — те же 100500 функций, но величина передается по значению или передается указатель — уверен, адрес будет везде разным. Со стандартом в руках не докажу, конечно, возможно и не прав.
СМ>Здесь имеет место быть просто ошибка MS (довольно старая) и делать какие-либо теоретические выкладки — глупо
Здравствуйте, Marty, Вы писали:
СМ>>какой-то бред. Полное не понимание, что передается и как. M>Ну я и писал имхо.
СМ>>Если верить Вашей логике, то и *Count нельзя использовать (т.к. там такой же адрес как и &Count), а это не так. M>Нет, не так. При взятии адреса указателя будет взят именно адрес указателя, а не адрес адресуемого этим указателем объекта. Можно попробовать — создать 100500 различно вложенных функций, в которые передавать ссылку и брать от нее адрес — думаю, результат будет везде одинаков. И второй вариант — те же 100500 функций, но величина передается по значению или передается указатель — уверен, адрес будет везде разным. Со стандартом в руках не докажу, конечно, возможно и не прав.
&int Count и *int Count передаются абсолютно одинаково уж в MS точно. для 32бит пихается адрес целого в стек.
Здравствуйте, Сергей Мухин, Вы писали:
СМ>>>Если верить Вашей логике, то и *Count нельзя использовать (т.к. там такой же адрес как и &Count), а это не так. M>>Нет, не так. При взятии адреса указателя будет взят именно адрес указателя, а не адрес адресуемого этим указателем объекта. Можно попробовать — создать 100500 различно вложенных функций, в которые передавать ссылку и брать от нее адрес — думаю, результат будет везде одинаков. И второй вариант — те же 100500 функций, но величина передается по значению или передается указатель — уверен, адрес будет везде разным. Со стандартом в руках не докажу, конечно, возможно и не прав.
СМ>&int Count и *int Count передаются абсолютно одинаково уж в MS точно. для 32бит пихается адрес целого в стек.
С этим утверждением не буду спорить, так как оно соответствует реальному положению вещей. Единственно, амперсанд не там поставлен.
СМ>т.е. все ваши слова в топку.
Ну может и в топку, но операция взятия адреса для параметра-ссылки и для параметра-указателя даст разные значения — в первом случае будет адрес реального размещения величины, во втором — адрес указателя на место реального размещения величины. Если считаете, что я не прав ( а я прав ), то приведите код, который опровергает мои утверждения.
[skip] M>Ну может и в топку, но операция взятия адреса для параметра-ссылки и для параметра-указателя даст разные значения — в первом случае будет адрес реального размещения величины, во втором — адрес указателя на место реального размещения величины.
Я правильно понимаю, что во втором случае размер этого самого указателя вычислить можно, а в первом — нельзя?
СМ>>&int Count и *int Count передаются абсолютно одинаково уж в MS точно. для 32бит пихается адрес целого в стек. M>С этим утверждением не буду спорить, так как оно соответствует реальному положению вещей.
отлично
> Единственно, амперсанд не там поставлен.
ага
СМ>>т.е. все ваши слова в топку. M>Ну может и в топку, но операция взятия адреса для параметра-ссылки и для параметра-указателя даст разные значения — в первом случае будет адрес реального размещения величины, во втором — адрес указателя на место реального размещения величины. Если считаете, что я не прав ( а я прав ), то приведите код, который опровергает мои утверждения.
я этого никогда не утверждал.
Но нам не надо получать этот адрес, нам надо адрес следующего параметра в каком-то массиве (например в стеке), компилятор мог бы подсуетиться и вычислить это сам, не обращая внимания на тип Count. Но стандарт этого не требует.
Здравствуйте, Dzirt2005, Вы писали:
M>>Ну может и в топку, но операция взятия адреса для параметра-ссылки и для параметра-указателя даст разные значения — в первом случае будет адрес реального размещения величины, во втором — адрес указателя на место реального размещения величины. D>Я правильно понимаю, что во втором случае размер этого самого указателя вычислить можно, а в первом — нельзя?
Я вас наверно неправильно понимаю, но я вас не понимаю ;
Размер указателя значения не имеет. Мы пытаемся получить не размер указателя, а адрес на стеке, от которого будем отсчитывать адреса аргументов, переданых через ... И в случае ссылки, мы получаем не адрес аргумента на стеке, а адрес объекта, на который ссылаемся.
SaZ:
SaZ>Следующий код не работает в msvc 2010, но работает в gcc:
Принципиальное отличие реализации va_start и va_arg у VC++ и GNU C++ состоит в том, что реализация у VC++ пытается получить адрес того места в памяти, на которое ссылается выражение, переданное вторым аргументом у va_start, для того чтобы потом на основе этого адреса отсчитывать адреса дополнительных аргументов функции (как тут уже описал Marty), в то время как у GNU C++ для получения адресов дополнительных аргументов функции привлекаются свои собственные встроенные операторы (реализуемые компилятором, а не библиотечными средствами), которых мало интересует, что там передали вторым аргументом va_start (см. наглядный пример) — компилятор сам в состоянии определить всё, что нужно для правильной работы, без подсказок.