А вот как "напечатать"-вывести в Serial указатель ?
- Войдите на сайт для отправки комментариев
Втр, 09/07/2013 - 22:05
Думал все просто, типа
Serial.println(&buffer);
а вот фиг там
Думал все просто, типа
Serial.println(&buffer);
а вот фиг там
а смысл?
указатель это число указывающее на память в дуине
наприемнике он не имеет смысла
указатель это число указывающее на память в дуиненаприемнике он не имеет смысла
Смысл то как раз имеется. Хочу проверить, вот такую конструкцию, правильно ли там все инкрементируется
не знаю как в winavr, в IAR адрес добывается вот так
тут же дело в понимании языка. объявляя любой длины буфер, компилятор запоминает только его первый элемент. другими словами, объявление буфера это и есть обявление адреса нулевого его элемента.
т.е.
buffer == &buffer[0]
отсюда и пляшем.
Думал все просто, типа
а вот фиг там
А вот так попробовать не пытались?
Понял, без указания цели, показалось странным намерение)
&buffer
имеет тип type*
и нет подходящего println, как писали выше надо привести к целому
О, спасибо ! Работает!
Ого, какие интересные результаты. Я думал, что когда объявляешь массив и увеличиваешь указатель на массив на единицу, то указатель инкрементируется на размер элемента массива. Нифига, оказывается на размер всего массива
Результат
2222
2306
2306
Он инкрементируется на величину sizeof(var)C
Чтобы на единицу надо так
Int buf[42];
Int* ptr;
ptr = &buf;
ptr +=1;//ptr сдвинется на sizeof (int)
Или вот так
Результат
2220
2222
Т.е. все абсолютно логично, если ссылка на сам массив, то при +1 указатель увеличивается на размер массива
А если указатель на элемент массива, то при +1 указатель увеличивается на элемент массива
мда. какой "увеличивается на размер массива"? это не из этой оперы.
В смысле не из той оперы ? Этож вроде классический Си.
При инкрементации указателя он увеличивается на размер объекта, на который указывает.
В случае, если указатель на массив, указатель как раз увеличивается на размер массива
А вот если указатель на элемент массива, то он увеличивается на размер элемента массива
та нет. любой инкремент типа ++ увеличивает только на единицу. и компилятору всё равно, указатель это или переменная.
Конструкция &buffer[0] + 1 обычно не используется, проще использовать buffer + 1, другой аналог &buffer[1].
Конструкция &buffer + 1 это вообще нонсенс, она указывает на адрес за последним элементом массива. Не рекомендую вообще пользоваться.
Еще примеры вполне корректного (с определенными ограничениями) использования:
С указателями аккуратней, выйти за пределы - как два пальца об асфальт.
та нет. любой инкремент типа ++ увеличивает только на единицу. и компилятору всё равно, указатель это или переменная.
Вот по поводу "на единицу" не надо путать. vlkam всё правильно сказал, на размер объекта.
Все верно, на единицу.
Только для char единица это байт, для int "единица" 2 байта, а для массива - размер массива.
Попробуйте запустить код :
2281
2282
2282
2292
не знаю. это мутка winavr. как он из адреса извлекает адрес добавляя единицу. возможно неправильная расстановка приоритетов.
Смотрим сюда.
Результат:
2282
2283
И почему при addr += 1 нифига не добавилось на 10?
Пример номер два.
Результат:
2282
2283
т.е. может надо указывать явно адрес элемента который хотим получить?
И пример номер три, который подтверждает мои слова что buffer это уже &buffer[0], т.е. уже содержит адрес! нулевого элемента и не надо никаких &... не? Смотрим.
Результат:
2282
2283
И никаких прибавлений на размер массива не наблюдается.
У тебя addr тип int a не int[10]
Тут приоритет операций - сперва адрес конвертируется в int, а только потом добавляется единица.
buffer+1 В скобки возьми, тогда сперва указатель увеличится, а потом конвертация произойдет
И это не "мутка avr", я это помню еще с Borland C++
Чтобы не париться с приоритетами, ставьте скобки, тогда будет как задумано
Тут приоритет операций - сперва адрес конвертируется в int, а только потом добавляется единица.
buffer+1 В скобки возьми, тогда сперва указатель увеличится, а потом конвертация произойдет
И это не "мутка avr", я это помню еще с Borland C++
ну взял в скобки
результат тот-же. собственно, почему ему быть другим?
я знаю, что надо сделать, чтобы закончить полемику. возьмите отладчик и пройдитесь. покажите код, где идет прибавление на размер массива, и в какой ячейке озу этот размер лежит. или вы хотите сказать, что если я создам сто массивов, у меня заберут кучу памяти под размеры для каждого. не сильно верится, но всё может быть.
результат тот-же. собственно, почему ему быть другим?
А вы определите несколько указателей:
char *cptr;
int *iptr;
long *lptr;
Присвойте им адрес буфера, добавьте к каждому из этих указателей по единичке и выведите результат(ы).
Получится ли у вас "тот-же" результат?
причем тут указатели? понятное дело, что если указатель объявить как long, то инкремент будет на четыре байта. причем тут массив? эта хрень пройдет и без массива. и адрес вытаскивается не в указатель, а в обычную переменную, которая не может инкрементироваться как ей хочется, а только на единицу.
да и вобще, че я парюсь. иар такое выражение не скомпилирует, выбъет ошибку
Error[Pe513]: a value of type "char (*)[3]" cannot be assigned to an entity of type "char"
winavr компилирует, но почему именно с таким результатом, известно наверное только ему и правильно сказал kisoft
"Конструкция &buffer + 1 это вообще нонсенс, она указывает на адрес за последним элементом массива. Не рекомендую вообще пользоваться."
и я щетаю это правильный ответ.
upd: вот только что проверил в CVAVR, он тоже такой записи не знает, так что это самоинициатива winavr, а не стандарт си. нет в си такой "чухни" где "+1" это прибавление на размер массива.
upd: вот только что проверил в CVAVR, он тоже такой записи не знает, так что это самоинициатива winavr, а не стандарт си. нет в си такой "чухни" где "+1" это прибавление на размер массива.
Я тоже так думал, потому что никогда не использовал эту странную конструкцию, даже в голову не приходило. Свои примеры (см. сообщение #14) проверял в MS Visual Studio C++ 2010 Express, там &buffer + 1 указывает, как я уже писал на первый элемент ПОСЛЕ массива. Так что это всё вписывается в стандарты. ;)
Если уж сравнивать работу компиляторов, нужно взять один пример и скомпилировать в разных средах, затем уже сравнивать результаты, сдается мне, что они будут одними и теми же. А то cейчас "спор" ни о чем.
По собственному опыту часто использую конструкцию (buffer + index) и, почти никогда &buffer[index]. На мой взгляд проще всего завести указатель uint8_t *ptr = buffer; и им оперировать, не забывая про выход за границы массива. Экономия на спичках дорого обходится.
Борланд С++ 1995 год
ну так я как-бы и проверил. winavr, IAR, CVAVR... последние такую запись не знают.
потом, стандарт C++ это уже далеко не С. Там уже ООП. И такая конструкция возможна. Точнее, конструкция
&buffer переделывается в &buffer[10], где 10 - это размер, объявленный при создании массива, тогда логично что +1 к этому делу указывает на следующий байт после массива. Так делает и winavr.
Но, надоело повторяться, это не прибавление на размер массива,т.к. &buffer + 2 не прибавить два раза по десять, а +3 не прибавит по три десятка, а прибавит эти числа только к адресу последнего элемента.
Всё, на этом заканчиваю, а то создается впечатление, что я сам себе что-то доказываю.
Борланд С++ 1995 год
Вы сами понимаете, что читаете? Увеличивается на размер связанного с ним типа! т.е. если массив объявлен как int, то увеличение будет на 2, если long, то на 4 внутри массива. Это логично! Но не на размер ВСЕГО массива! Неужели это так трудно понять.
И второе, в вашей записи
Serial
.println((
int
)&buffer);
нет и намека на указатель, а адрес записывается в обычную переменную.
Мда. Каша в голове - она такая каша.
Предположим, у нас есть несколько переменных:
char myChar;
int myInt;
long myLong
char buffer[10];
Тогда конструкция "&myChar" будет иметь тип "указатель на char", "&myInt" - "указатель на int", "&myLong" - укащатель на long, а "&buffer" - "указатель на массив из десяти элементов типа char"
Следующий шаг - конструкция &var + 1 обозачает "адрес ячейки памяти, в котором будет храниться следующая после var" переменная.
Пусть наш чар лежит по адресу 0x1000, по какому адресу будет лежать следующая за ним переменная? Правильно, 0x1001.
А если по этому адресу лежит не чар, а инт, по какому адресу будет следующая переменная? 0x1002. А если там лежит переменная типа "массив из десяти чаров?" - 0x100A
И второе, в вашей записи
Serial
.println((
int
)&buffer);
нет и намека на указатель, а адрес записывается в обычную переменную.
Нету в языках программирования C и C++ типа "обычная переменная". А каждое выражение имеет какой-то тип, вот незадача.
Внимание вопрос - какой тип имеет выражение "&buffer"?
Следующий шаг - конструкция &var + 1 обозачает "адрес ячейки памяти, в котором будет храниться следующая после var" переменная.
Поправочка, это если выравнивание по байтам, а если нет, то не факт, что следующая переменная будет храниться по этому адресу, может быть пустое место. Я не даром писал, что на "следующий элемент после массива" - это не значит, что на следующую переменную. Что я, собственно и наблюдал в MS VS C++.
Уфф, всё, я пас :)
Предположим, у нас есть несколько переменных:
char myChar;
Пусть наш чар лежит по адресу 0x1000, по какому адресу будет лежать следующая за ним переменная? Правильно, 0x1001.
А если по этому адресу лежит не чар, а инт, по какому адресу будет следующая переменная? 0x1002. А если там лежит переменная типа "массив из десяти чаров?" - 0x100A
нет. следующая относительно первого элемента будет ровно на один тип больше. если в массиве чары, то следующая будет 0x1001, если инты, то 0x1002.
если у вас есть уверенность в ваших предположениях, давайте код. будем посмотреть.
Внимание вопрос - какой тип имеет выражение "&buffer"?
всмысле тип? если он (буфер) размещен в конце карты памяти в 32Гб, то может быть и long long.
У меня не предположения. Я первым делом все проверил и посмотрел результаты -)
Вот код:
Вот вывод:
Компилятор:
>gcc --version
gcc 4.4.4 20100726 (Red Hat 4.4.4-13)
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ОС:
> cat /etc/redhat-release
Red Hat Enterprise Linux Client release 5.5 (Tikanga)
Выше kisoft уже писал про поведение MSVS.
всмысле тип? если он (буфер) размещен в конце карты памяти в 32Гб, то может быть и long long.
Тип - это такое базовое понятие многих языков программирования, в том числе и C/C++.
Тип этот никоим образом не зависит от того, где именно хранятся данные.
И тип выражения &var никогда и ни при каких условиях не будет long long.
Да, этот адрес, в зависимости от платформы может иметь длину 2, 4 и 8 байт (а изредка в экзотических случах, даже 1 байт), но тип всегда останется "указатель на <тип переменной var>".
У меня не предположения. Я первым делом все проверил и посмотрел результаты -)
Вот код:
Вот вывод:
это не доказательство. Вы отняли от последнего элемента массива первый. Это понятно.
Доказательсво это когда
printf("%lld\n" , (long long)(&buffer + 1 ) // Здесь получаете 10
а вот здесь
printf("%lld\n" , (long long)(&buffer + 2 ) // получаете 20, как тут во весь голос кричат
В противном случае... короче понятно.
Вы сами понимаете, что читаете? Увеличивается на размер связанного с ним типа! т.е. если массив объявлен как int, то увеличение будет на 2, если long, то на 4 внутри массива. Это логично! Но не на размер ВСЕГО массива! Неужели это так трудно понять.
Тут, IMHO, небольшой винигрет. Не важно "как массив объявлен", важно "как указатель объявлен".
Если у вас "указатель на int", то его инкремент будет сдвигать на 2 байта. А вот если "указатель на массив _неважно_чего_", то инкремент будет сдвигать на "размер массива" (само собой размер масива должен быть известен на момент компиляции).
Вообщем рояль играет "тип указателя". Мы же при его объявлении указываем "на объекты какого типа он указывает".
Ну и еще, конечно, тут добавляет путаницы, что "под капотом", сами массивы реализованны как указатели :(
Поэтому с помощью приведения типов можно довольно безболезненно конвертировать скажем "char*" в "char[]" и обратно. Лично я для себя, если честно, массивы так и воспринимаю - как более наглядный синтаксис для указателей. Вообщем, в большинстве случаев, нужно просто просто выборать "что тебе понятней", массивы или указатели (но знать нужно и то и другое :). И старатся их не смешивать. Писать "однотипно".
я не отрецаю, но код в пример я обязан попросить. и желательно оперируя только & как в теме, а не условным присовением "*", но в любом случае на получние знаний не повлияет. я только за.
upd.
Поэтому с помощью приведения типов можно довольно безболезненно конвертировать скажем "char*" в "char[]" и обратно. Лично я для себя, если честно, массивы так и воспринимаю - как более наглядный синтаксис для указателей.
я тоже честно, массивы воспринимаю уже глядя на ячейки памяти МК в озу. Простые тупые ячейки с размером в байт. Никаких чудес. )
кстати. запостю на изи. мож вразумительный ответ получим.
Ок, вот Вам еще один код, как просили.
Вывод:
773864df, 773864e0
773864dc, 773864de
773864d8, 773864dc
773864c0, 773864ca
PS: У меня вопрос - какова цель жанного обсуждения? Вы хотите что-то доказать или все-же уяснить для себя ответ на вопрос?
Если доказать, до, извините, я пас и в дльнейшем обсужднении учавствовать не буду, ибо я просто знаю правильный ответ на этот вопрос, причем ртвет этот подтвержден как теорией, так и практикой.
Если уяснить для себя ответ - давайте начнем с того, ответ на какой именно вопрос?
я хочу увидеть этот механизм, о котором все говорят, уже даже вроде сам себя убедил, что какими-то махинациями этого можно добиться, но никто не приводит пример, только слова. И ладно если бы это было в одном посте, а так практически через пост упоминается эта ерунда.
и Вы, кстати, тоже не устаете приводить очевидную вещь в виде строки
printf
(
"%x, %x\n"
, (
long
long
)(&buffer ), (
long
long
)(&buffer + 1 ) );
я прекрасно знаю что это, но это не прибавление указателя на размер массива. прибавте мне число два к указателю массива и покажите результат, что он действительно равен двум массивам.
Так вроде как раз с этого и началось все, там пример кода есть и возвращаемый результат. У Вас он не такой ? :
http://arduino.ru/forum/programmirovanie/vot-kak-napechatat-vyvesti-v-se...
окей. уговорили. тогда почему iar и cvavr не хавают эту запись?
&buffer + 1
и говорят тчо надо обратиться к элементу? [] либо не использовать &, т.к. buffer это ужа сам по себе указатель. Типа winavr хоть и бесплатный, но даже покруче чем IAR выходит? )) шутка.
buffer указатель
&buffer адрес указателя. Т.е указатель на указатель
И как же по Вашему "указатель на указатель" инкрементируется на размер буфера ?
В данном случае, &buffer - это все таки не указатель на укащатель, а указатель на массив жестко заданной длины. При инкременте, указатель увеличивается на
sizeof() от того типа, на который указывает. Sizeof от типа "массив из десяти чаров" - это 10. (Ключевой момент здесь то, что 10 часть определения типа, известная на этапе компиляции).
[quote=__Alexander]
Сорри,что-то проглючило...
Выводит:
Вообщем указатель это такия фигня "два в одном". И какой-то адресс в памяти и "что там находится" в одном флаконе. Это скорее "нечто" которое информацию о том как интерпретировать некий участок памяти (где он находится, какого размера, его составные части если это объект или структура и т.п.)
Одним словом, я признаю свое поражение в данном споре, т.к. выяснил одну важную деталь, до сегодняшнего дня конструкция &buffer + 1 игнорилась всеми компиляторами для AVR, кроме winavr, который является основой ардуино иде. Видимо в свете последних дней, когда существуют множиство языков с ООП, в него были встроены данные изменения и поэтому компиляция проходит без проблем и действительно вычисляется как вы и говорите. Пролистав книги по си до сегодняшнего дня, все указатели писались &buffer[x], т.е. с указанием на конкретную ячейку или просто buffer, т.к. это уже само по себе указатель. Всё, устал. )
Одним словом, я признаю свое поражение в данном споре
Вот про это и поспорим :) Поражение - как правило термин игр с нулевым или отрицательным балансом.
А тут у нас, скорее речь идет про "игру с положительным балансом". Ведь у вас же "ничего не убыло". Наоборот - прибавилось понимание :)
Все зависит от того какие цели вы ставили... термин "поражение" имеет смысл только если целью было поднять свое ЧСВ. Но... в этом бы случае вы бы вряд ли признали "поражение". А значит - нет никакого поражения ;)