Что означает &buffer[i*4]???
- Войдите на сайт для отправки комментариев
Втр, 29/01/2019 - 04:38
Помогите пожалуйста разобраться, что означает &buffer[i*4]???
Вот функция целиком
for (int i=0; i < 4; i++) { //data is writen in blocks of 4 bytes (4 bytes per page) status = (MFRC522::StatusCode) mfrc522.MIFARE_Ultralight_Write(pageAddr+i, &buffer[i*4], 4); if (status != MFRC522::STATUS_OK) { Serial.print(F("MIFARE_Read() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return; } }
та же функция...
StatusCode MIFARE_Ultralight_Write (byte page, byte *buffer, byte bufferSize)
Её тип StatusCode? То есть при return она возвращает код определенной команды?
С первым параметром всё понятно. Адрес страницы увеличивается в цикле за счет i++. Верно?
Третий параметр это размер буфера в байтах? Или нет?
А вот что означает второй параметр - для меня "темный лес"? Зачем там значок "&"? Это указатель на адрес памяти? И самое непонятное почему там стоит [i*4]? Это умножение значения переменной i на 4?
Не могу понять, зачем её умножать?
Объясните пожалуйста новичку! Заранее спасибо!
Привожу код примера целиком:
/* mifare ultralight example (25-02-2018) * * RFID-RC522 (SPI connexion) * * CARD RC522 Arduino (UNO) * SDA ----------- 10 (Configurable, see SS_PIN constant) * SCK ----------- 13 * MOSI ----------- 11 * MISO ----------- 12 * IRQ ----------- * GND ----------- GND * RST ----------- 9 (onfigurable, see RST_PIN constant) * 3.3V ----------- 3.3V * */ #include <SPI.h> #include <MFRC522.h> #define SS_PIN 10 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance MFRC522::StatusCode status; //variable to get card status byte buffer[18]; //data transfer buffer (16+2 bytes data+CRC) byte size = sizeof(buffer); uint8_t pageAddr = 0x06; //In this example we will write/read 16 bytes (page 6,7,8 and 9). //Ultraligth mem = 16 pages. 4 bytes per page. //Pages 0 to 4 are for special functions. void setup() { Serial.begin(9600); // Initialize serial communications with the PC SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 card Serial.println(F("Sketch has been started!")); memcpy(buffer,"HELLO WORLD! ;-)",16); } void loop() { // Look for new cards if ( ! mfrc522.PICC_IsNewCardPresent()) return; // Select one of the cards if ( ! mfrc522.PICC_ReadCardSerial()) return; // Write data *********************************************** for (int i=0; i < 4; i++) { //data is writen in blocks of 4 bytes (4 bytes per page) status = (MFRC522::StatusCode) mfrc522.MIFARE_Ultralight_Write(pageAddr+i, &buffer[i*4], 4); if (status != MFRC522::STATUS_OK) { Serial.print(F("MIFARE_Read() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return; } } Serial.println(F("MIFARE_Ultralight_Write() OK ")); Serial.println(); // Read data *************************************************** Serial.println(F("Reading data ... ")); //data in 4 block is readed at once. status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(pageAddr, buffer, &size); if (status != MFRC522::STATUS_OK) { Serial.print(F("MIFARE_Read() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return; } Serial.print(F("Readed data: ")); //Dump a byte array to Serial for (byte i = 0; i < 16; i++) { Serial.write(buffer[i]); } Serial.println(); mfrc522.PICC_HaltA(); }
Нашел его здесь
что означает &buffer[i*4]???
Адрес i-того 4-х байтового блока в массиве buffer.
Ну, наверное, пейсатель скретча создаст функцию вычисления uint16_t crc16=getCRC(buffer, sizeof(buffer)-sizeof(uint16_t)) и поместит его в последние два байта - *((uint16_t*) &buffer[sizeof(buffer)-sizeof(uint16_t)]) = crc16;
Конечно это потом будет "автоматически".
*((uint16_t*) &buffer[sizeof(buffer)-sizeof(uint16_t)]) = crc16;
Если это медленно и распевно произнести вслух, то можно вызвать демона... ну не самого главного, но все же... ;)))
Я бы себя убил за такую запись.
Запишите проще и чтобы там были все элементы, которые пытается разучить джуниор. Впитаю ваш опыт, так скыть.
Нет уж, ваш способ универсальный и переносимый, спору нет. Но он неудобочитаемый. Однако, когда пишешь для конкретного железа, можно просто: buffer[sizeof(buffer)-2] = LOWBYTE(crc16); buffer[sizeof(buffer)-1] = HIGHBYTE(crc16); или какой там у вас big-little-endian. Или ещё сто способов, без вложенных разыменований. Причём для 8-битного контроллера - это нативнее.
Ну, за нативность я не буду говорить - надо посмотреть, конечно, что там в ассемблер прилетит. Мошт с lowByte() / highByte() то на то и выйдет. Плюс еще с эндианами разбирайся... За нечитаемость не спорю. Но, раз уж человек хотел поупражняться с адресацией, то я ему для закрепления написал пример.
Эти макросы компилятор обычно превращает просто в младший или старший байт, ну или в их адрес, если адресация памяти не прямая. Думаю, в моём примере будет две или три ассемблерных инструкции. Было бы интересно вашу запись посмотреть, подозреваю что то же самое получиться, gcc умный. Вроде где-то натыкался как сказать IDE, чтобы асм сразу делала?
Ну, наверное, пейсатель скретча создаст функцию вычисления uint16_t crc16=getCRC(buffer, sizeof(buffer)-sizeof(uint16_t)) и поместит его в последние два байта - *((uint16_t*) &buffer[sizeof(buffer)-sizeof(uint16_t)]) = crc16;
Конечно это потом будет "автоматически".
Помогите пожалуйста перевести это на человеческий язык, а то мне кажется, что сам не осилю :)
Для начала строчка
Это создание шестнадцати-битной переменной, с названием crt16. Правильно?
В эту переменную заносится выражение справа. В нём функция getCRC, которая есть в стандартной библиотеке С++? Она высчитывает контрольную сумму из того, что в скобках.
sizeof(buffer) размер переменной buffer в байтах
sizeof(uint16_t) размер типа данных uint16_t 16 бит или 2 байта. Правильно?
(sizeof(buffer) - sizeof(uint16_t)) означает вычитание из размера буфера 16 бит или 2 байт?
А как расшифровать это
Значок * обозначает создание указателя? Чтобы понять, куда он указывает, нужно посчитать, что в скобках?
Скобок тут куча, и я даже не совсем понимаю, в какой последовательности это обрабатывается компилятором!
Что означает (uint16_t*)? Зачем там звездочка?
"Козюльский! Перестаньте сказать!" (с)
Конечно, вариант Садмана1 гораздо читаемее и легче понимаем, что та околесица, которую написал Шварц78.
Для микроконтроллеров НЕ ПИШУТ переносимый код. Вот потому, что это нахер никому не нужно - переносить некуда, весь код контроллера насквозь аппаратно-зависим от конкретного контроллера. Поэтому и union и адресная арифметика с конкретным порядком байт - НОРМА для контроллеров.
Уже тут на фолруме, только на моей памяти, раза три копья ломали. Итог - не нужно тащить в эмбеддинг всю херату из большого програмирования для компьютеров.
-----
дополню: и не надо стесняться писать просто 2, вместо sizeof(uint16_t) ! ;))) Вот это выглядело глупо.
Такие выражения надо справа налево читать.
buffer[
sizeof
(buffer)-
sizeof
(uint16_t) - это элемент в массиве, где дожна лежать контр. сумма. & - это взятие адреса сего элемента.
(uint16_t*) - это для компилятора, приведение типа этого адреса к указателю на тип uint16_t. Ну и * - разыменование, то есть значение по адресу указателя. Теперь мы имеем указатель на uin16_t, по адресу которого присваиваем значение crc16/Уважаемый, поясните за околесицу. Я вообще-то только для контроллеров и программировал(почти), и про непереносимость кода могу много рассказать. Так как Садаман никто для контроллеров не пишет. А вот почему у меня околесица? Я начинал с ассемблера, и примерно понимаю какой код даёт компилятор для 8-биток, а вы?
И ещё у вас взаимоисключающие параграфы, извините уж, что оцениваю ваше психофизическое состояние))
А как расшифровать это
Значок * обозначает создание указателя? Чтобы понять, куда он указывает, нужно посчитать, что в скобках?
Скобок тут куча, и я даже не совсем понимаю, в какой последовательности это обрабатывается компилятором!
Что означает (uint16_t*)? Зачем там звездочка?
Эти макросы компилятор обычно превращает просто в младший или старший байт, ну или в их адрес, если адресация памяти не прямая. Думаю, в моём примере будет две или три ассемблерных инструкции. Было бы интересно вашу запись посмотреть, подозреваю что то же самое получиться, gcc умный. Вроде где-то натыкался как сказать IDE, чтобы асм сразу делала?
Да я бы вообще это сделал через ((struct*) )->... если честно. Мне так понятней даже.
А IDE ASM не отдает. Надо как-то там попрыгать с командной строкой, чтобы из объектника дизассемблировать.
https://godbolt.org/z/LleiJi
Насколько я понимаю, вот этот кусок:
А вот вариант с lowByte/highByte: https://godbolt.org/z/y0TKa8
Уважаемый, поясните за околесицу.
lowByte() и highByte()
Это не удобство, а чушь собачья. Недаром в самой avr-libc это глупости нету.
Корни этой премудрости растут в извращенном желании ардуино-сообщества "впрясть в телегу вола и трепетную лань". То есть построить единую экосистему и для АВР и для АРМ и ЕСП8266 и ещё хрен-знает-чего.
Получилось то, что получилось - замечательная вещь для популяризации идеи МК. Но, как только человек изучает программирование достаточно (например узанет, зачем нужны ссылки ;))))) -без обид!), он перестает пользоваться большей частью этой экосистемы.
Именно так. Но, поскольку массив и crc16, то где-то здесь явно последовательная передача(serial), и самое время подумать, в каком порядке читает uint16_t принимающая машина (little endian или big).
lowByte() и highByte()
Это не удобство, а чушь собачья. Недаром в самой avr-libc это глупости нету.
Во всех 8-битных контроллерах и компиляторах для них эти макросы так или иначе определены, и очень прозрачно превращаются именно в старший или младший байт. Для 16-битного int, конечно. Для меня это как данность уже. С MSP430 или ARM32 буде конечно не так, но здесь у нас AVR в основном. Ну и посмотрите как это выглядит в Arduino.h:
Вполне предсказуемо.
А IDE ASM не отдает. Надо как-то там попрыгать с командной строкой, чтобы из объектника дизассемблировать.
Не нужно ходить на тот сайт, компиляция сильно зависит от настроек линковщика и оптимизатора.
/ПУТЬ-К-ИДЕ/hardware/tools/avr/bin/avr-objdump -S ИМЯ-СКЕТЧА.ino.elf >> Куда-тебе-надо.S
Запустить в том каталоге, куда ИДЕ складывает все после компиляции
lowByte() и highByte()
Это не удобство, а чушь собачья. Недаром в самой avr-libc это глупости нету.
Во всех 8-битных контроллерах и компиляторах для них эти макросы так или иначе определены, и очень прозрачно превращаются именно в старший или младший байт. Для 16-битного int, конечно. Для меня это как данность уже. С MSP430 или ARM32 буде конечно не так, но здесь у нас AVR в основном. Ну и посмотрите как это выглядит в Arduino.h:
Вполне предсказуемо.
;))) А ты забавный! Спасибо, дорогой, я уже их видел... краем глаза. ;))))
Я не о том, как они определены. А о том, что их использовать не стоит. Хотя это личное дело каждого.
Например: ты насколько знаешь команды АВР? Это не подколка, не принимай на свой счет. Просто сдвиг на 8 в авр БЕЗ оптимизации - это ровно 8 сдвигов. ;)))
Не нужно ходить на тот сайт, компиляция сильно зависит от настроек линковщика и оптимизатора.
Я бы сказал - от оптимизатора, линковщик только линкует.
Запустить в том каталоге, куда ИДЕ складывает все после компиляции
О, за это спасибо, я когда-то ходил этим путём, но уже забыл, а гуглить лень на ночь глядя.
Не нужно ходить на тот сайт, компиляция сильно зависит от настроек линковщика и оптимизатора.
Да я в научные изыскания не хочу погружаться. Так, прикинуть быстро что почём.
Думаю не открою тебе секрета, если скажу, что препроцессор не станет ничего сдвигать, а компилятор тем более не идиот. Он просто подставит старший или младший байт.
И потом, как писать - личное дело каждого. Я тоже люблю объединения, они однозначнее. И ваще - препроцессор зло. Хотя есть такие штуки, которые очень вкусные с препроцессором.
Не нужно ходить на тот сайт, компиляция сильно зависит от настроек линковщика и оптимизатора.
Я бы сказал - от оптимизатора, линковщик только линкует.
Пожалуйста, не нужно спорить... по крайней мере, пока со ссылками не разберешся ;))).
-flto - опция линковщика. Ты не поверишь, но так и называццо: link time optimization ;))))
Думаю не открою тебе секрета, если скажу, что препроцессор не станет ничего сдвигать, а компилятор тем более не идиот. Он просто подставит старший или младший байт.
Ты не научился читать? Я написал - БЕЗ оптимизации. Так без нее компилятор ничего не уберет из авторского кода, не сократит и не заменит.
В командах АВР нет сдвига с параметром, только на 1 бит.
Никогда, на этом форуме, не нужно со мной спорить.... ну пожалуйста-пожалуйста-пожалуйста!!!! ;)))
Если я берусь о чем-то рассказывать, то это из области педагогики. Просто о том, "из чего, на самом деле, тетька сделана". Все для народа стараюсь... руки в кровь стёр! ;)))
Ну, предположим что lto работает и для avr. Доволен? Я не спорю.
Ты не научился читать? Я написал - БЕЗ оптимизации. Так без нее компилятор ничего не уберет из авторского кода, не сократит и не заменит.
В командах АВР нет сдвига с параметром, только на 1 бит.
Никогда, на этом форуме, не нужно со мной спорить.... ну пожалуйста-пожалуйста-пожалуйста!!!! ;)))
Да, эту ремарочку я заметил, и подумал что за неё ты и уцепишься, когда я отвечу. Ну что тебе сказать про Сахалин... ))
Про машинные команды мне не рассказывай, уважь и ты меня.
Как я и написал выше, не спорю, мне просто даже любопытно)
ОК, я - спать, а то мне еще 40 минут под кислородом лежать, а в Мск уже почти полночь... старый я и больной... да и самогонка кончилась ;). Удачи.
----
ЗЫ: Про ссылки - Женя не стал тебя в той теме сильно грузить, но при использовании лямбда-функций без них очень будет трудно.
Я тоже спать, а про ссылки я ещё почитал, и немножко осознал чем они лучше указателей. Буду дальше учиться) Мне бшаблоны ещё понять, куда мне до лямбды. Очень я современное языкознание запустил. Спокойной.
Ты не научился читать? Я написал - БЕЗ оптимизации. Так без нее компилятор ничего не уберет из авторского кода, не сократит и не заменит.
В командах АВР нет сдвига с параметром, только на 1 бит.
wdrakula, там сдвигом препроцессор заведует, который подставит компилятору уже вычисленные значения. Оптимизация туть ни при чём.
сдвигом препроцессор заведует, который подставит компилятору уже вычисленные значения. Оптимизация туть ни при чём.
Не-не-не. Препроцессор только подставами занимается. Известно ведь, если написать #define x 1+1, а потом x = x * 10; - получим 11, а не 20.
сдвигом препроцессор заведует, который подставит компилятору уже вычисленные значения. Оптимизация туть ни при чём.
Не-не-не. Препроцессор только подставами занимается. Известно ведь, если написать #define x 1+1, а потом x = x * 10; - получим 11, а не 20.
Я тут утром, в мрачном расположении духа, поглядел на варианты компиляции сдвигов с разными
..... не стану рассказывать. Это любопытно для эрудиции. x<<8 нет, не 8 сдвигов, все-таки! Но x<<3 сильно удивит!
Это ни в коем случае не претензия к GCC! Скорее просто любопытно и весело.
Ты не научился читать? Я написал - БЕЗ оптимизации. Так без нее компилятор ничего не уберет из авторского кода, не сократит и не заменит.
В командах АВР нет сдвига с параметром, только на 1 бит.
wdrakula, там сдвигом препроцессор заведует, который подставит компилятору уже вычисленные значения. Оптимизация туть ни при чём.
Ну да. Это я сдура ляпнул.
Так что в итоге - экономней пользоваться вызовом демона, struct или highByte() ?
Помучался я немного с оптимизатором пока удалось честно скомпилировать. В общем - одинаковый код, как я и думал. Вот ваш:
А вот мой:
И ваще - препроцессор зло. Хотя есть такие штуки, которые очень вкусные с препроцессором.
Сами Вы зло! Забыли классику?
"В "Си" ... введен полезный тип данных "указатель" (pointer). Получается, как будто соединены воедино лучшие части языка Фортран и Ассемблера, не говоря уже о более творческих применениях оператора #DEFINE".
Я ахреневаю, дорогая редакция.
Я ахреневаю, дорогая редакция.
Иногда полезно своё ахреневание излить наружу. И вам легче, и волки целы.
Сами Вы зло! Забыли классику?
"В "Си" ... введен полезный тип данных "указатель" (pointer). Получается, как будто соединены воедино лучшие части языка Фортран и Ассемблера, не говоря уже о более творческих применениях оператора #DEFINE".
Я же сказал - есть очень интересные мне вещи... С препроцессором.
Так как Садаман никто для контроллеров не пишет. А вот почему у меня околесица? Я начинал с ассемблера, и примерно понимаю какой код даёт компилятор для 8-биток, а вы?
Тюююю.... Пишут еще как. Я так пишу, когда нужна переносимость. А она бывает нужна, что бы, кто бы не говорил. Да же если учесть что в ардуино IDE есть и DUE и ESP с конца на конец.
И я начинал с ассемблера и мне кажется, что получится после компилятора... Но заметьте... Мне кажется, а вы прям так уверены :)
Представить адрес куска байтового массива как адрес какой нибудь 16 битной переменной, вполне себе нормальный подход. Будет быстрый и короткий код в результате.
А вот утверждать, что размер инта ДВА байта, я бы не стал :(
Тюююю.... Пишут еще как. Я так пишу, когда нужна переносимость. А она бывает нужна, что бы, кто бы не говорил. Да же если учесть что в ардуино IDE есть и DUE и ESP с конца на конец.
И я начинал с ассемблера и мне кажется, что получится после компилятора... Но заметьте... Мне кажется, а вы прям так уверены :)
Я начинал с ассемблера, и примерно понимаю
Для 16-битного int, конечно.
А я не только для вас писал.... В любом случае в записях оперирующих значением указателя, ИМХО, следует избегать циферок связанных с размером данных, используйте sizeof ! Так по крайней мере будет понятен смысл написанного.
А я не только для вас писал.... В любом случае в записях оперирующих значением указателя, ИМХО, следует избегать циферок связанных с размером данных, используйте sizeof ! Так по крайней мере будет понятен смысл написанного.
Ды тогда ты мне писал! ;)))
Тут "каждый дрочит, как он хочет" (с).
1.МК это не комп, если ты пишешь код под АВР, то его невозможно никуда перенести.
2. Проекты на МК - небольшие по объему, в силу того, что памяти в МК мало, следовательно автор у них один, он и тимлид, и кодер и тестер ;), читаемость для чего/кого? Для кота? ;)) (его Чавес зовут)
Если выкладывать ни гитхаб или для заказчика писать - тогда другое дело.
---------------
Ну и пункт три: там было написано: sizeof(uint16_t), а не просто int. Согласись, что узнавать размер 16 бит это уже немножко перебор, в отличии от int.
Захотелось чуток дополнить
На самом деле, узнавать размер int - тоже странновато. Что нам это даёт? Вон, например:
Если в какой-то момент поймём, что для items нам int не хватает и захотим поменять на long, то если написано sizeof(items[0]), то поменять тип достаточно в строке №2 и всё, а если написано sizeof(int), то надо не забыть ещё и в строке №7 поменять.
Общее правило: писать именно то, что тебя на самом деле интересует, а не использовать какие-то дополнительные знания об этом объекте. Интересует размер элемента массива - вот так и пишем, а уж int он там или ещё чего - какая разница?
Евгений Петрович! Вот так, помаленечку, шажок за шажком и приучите нас к хорошему стилю )))
Общее правило: писать именно то, что тебя на самом деле интересует, а не использовать какие-то дополнительные знания об этом объекте. Интересует размер элемента массива - вот так и пишем, а уж int он там или ещё чего - какая разница?
А вот с этим я полностью согласен!
Коллеги, что ж вам этот sizeof(uint16_t) спать не дает... Я его написал для того, чтобы визуально сформировать у ТС понимание того, на сколько делать отступ назад от конца массива. Напиши 2 - пришлось бы объяснять, откуда эта константа и что код с ней тоже "так себе" по понимаемости. Я уже упоминал, что сам предпочитаю помещать crc через структуру - в этом случае вычисления смещений не требуются. Однако основной вопрос был про указатели, посему пришлось высасывать из пальца пример.
Если выкладывать ни гитхаб или для заказчика писать - тогда другое дело.
Если пишешь для себя, то этого никто не должен видеть. А там действительно, кто как хочет. Можно хоть рисовать.
Вот правильнее всех Евгений написал.
Если пишешь для себя, то этого никто не должен видеть. А там действительно, кто как хочет. Можно хоть рисовать.
Вот правильнее всех Евгений написал.
Если пишешь один, вы хотели сказать. И сам себе ОТК. Показывать можно, если не стыдно, вопрос ответственности, т.е. работает ли код, как надо. Если работает - вы молодец, если не работает - то все отмазки про чистоту языка, переносимость, красоту и новизну - не канают.
ЕвгенийП на то и профессор, чтобы правильно писать.
Если не можешь писать правильно, пиши неправильно.©