В Keil - результат компиляции в листинге с выводом на Ассемблере. Тестовый код на ADuC7024(ядро ARM7TDMI), без заливки в контроллер. Keil uVision4.
В принципе может с оптимизацией, но конструкция типа: Код (C++): uint8_t *b = buff + 3; предполагает, что вместо тройки может быть вообще переменная, а не константа, потому как есть операция сложения. В целях оптимизации кода, и если это не переменная, то компилятор "натравливается" для получения сразу адреса. А в конструкции: Код (C++): uint8_t *b = &buff[3]; "натравливать" не надо, конечно если это константа - та самая тройка. Но если это переменная то как и в предыдущем случае и с точки зрения Ассеблера они будут идентичны.
я про что и говорю - из такой записи абсолютно не очевидно, что buff - это массив. А запись: Код (C++): uint8_t *b = &buff[3]; абсолютно однозначна.
Я проверял на древнем MS C v.6.0 там код одинаковый. Код (C++): main() { char buff[] = "Hello"; char * b1; char * b2; _asm mov ax,ax; b1= &buff[3]; _asm mov ax,ax; b2= buff+3; _asm mov ax,ax; printf ("\n\rb1=%lp,b2=%lp\n\r", (void far *)b1,(void far *)b2); } ; Line 7 mov ax,ax ; Line 9 lea ax,WORD PTR [bp-5] mov WORD PTR [bp-2],ax ;b1 ; Line 11 mov ax,ax ; Line 13 lea ax,WORD PTR [bp-5] mov WORD PTR [bp-10],ax ;b2 ; Line 15 mov ax,ax
Поздравляю! Умный компилятор! Не "натравливали" его на оптимизацию? Говорил про это в #63 кстати если не сложно (вы пользуетесь x86) проверьте: Код (C++): uint64_t TS; TS = (*(uint64_t*)(&buff[3])); Меня интересует "выравнивание" (это не по этой теме) как 32/64 битных системах и 8 битных (ардуино). Будет ли необходимо выравнивание для 8-ми битных. Ардуины(IDE) под рукой нету(она на малине и запускать долго - в устройстве на колёсах). Для int64_t на ардуине обязательно выравнивать кратно 8 байт??? Если не затруднит дайте знать. Спасибо!
Оптимизация по умолчанию. Дополнительно не задавал. В нем 64 битных целых нет, проверил на 32 битной - все Ок. Спойлер: Результат: Код (C++): main() { char buff[] = "1234567890"; char * b1; char * b2; unsigned long TS; _asm mov ax,ax; b1= &buff[3]; _asm mov ax,ax; b2= buff+3; _asm mov ax,ax; TS = (*(unsigned long *)(&buff[3])); _asm mov ax,ax; printf ("\n\rb1=%lp,b2=%lp\n\r", (void far *)b1,(void far *)b2); printf (" size = %u TS = %lx \n\r", sizeof(TS), TS); } Код (Text): $SG103 DB '1234567890', 00H $SG108 DB 0aH, 0dH, 'b1=%lp,b2=%lp', 0aH, 0dH, 00H $SG109 DB ' size = %u TS = %lx ', 0aH, 0dH, 00H _DATA ENDS _TEXT SEGMENT ASSUME CS: _TEXT ; Line 1 ; Line 2 PUBLIC _main _main PROC NEAR push bp mov bp,sp mov ax,20 call __aNchkstk push di push si ; buff = -14 ; b1 = -2 ; b2 = -16 ; TS = -20 ; Line 3 lea di,WORD PTR [bp-14] ;buff mov si,OFFSET DGROUP:$SG103 mov ax,ss mov es,ax mov cx,5 rep movsw movsb ; Line 8 mov ax,ax ; Line 10 lea ax,WORD PTR [bp-11] mov WORD PTR [bp-2],ax ;b1 ; Line 12 mov ax,ax ; Line 14 lea ax,WORD PTR [bp-11] mov WORD PTR [bp-16],ax ;b2 ; Line 16 mov ax,ax ; Line 18 mov ax,WORD PTR [bp-11] mov dx,WORD PTR [bp-9] mov WORD PTR [bp-20],ax ;TS mov WORD PTR [bp-18],dx ; Line 20 mov ax,ax C:\C600\WORK\test>qq5 b1=0EF9:0D95,b2=0EF9:0D95 size = 4 TS = 37363534 C:\C600\WORK\test>
можно и с 32 битными интами, только тогда кратно 4-м байтам выравнивание... а проверить с нечётным расположением в массиве. У меня вот засада с этим. Передаю данные от устройства к устройству...там в шапке int64_t - время в секундах от 1970г. Передаю на одной платформе одно, а принимаю бардак на другой платформе(_PKT_CLCK). Но вот сейчас сделал определение расположения так: Код (C++): // карта шапки пакета #define _PKT_SIZE 0x00000000 //(pos 0) 4 байта(32bit) размера пакета #define _PKT_TIME 0x00000004 //(pos 4) 8 байт(64bit) - метка времени(время в BIN) #define _PKT_TYPE 0x0000000C //(pos 12) 1 байт - тип данных #define _PKT_FTYPE 0x0000000D //(pos 13) 1 байт - формат типа данных #define _PKT_CMD 0x0000000E //(pos 14) 1 байт - команда (код операции) #define _PKT_ANS 0x0000000F //(pos 15) 1 байт - ответ (результат выполнения) #define _PKT_CLCK 0x00000010 //(pos 16) 8 байт(64bit) - тик времени #define _PKT_DATA 0x00000020 //(pos 32) начало данных вроде нормально(надо подумать про расположение _PKT_TIME - он кратен 4-м). Обмен между малиной3 и PC(Debian10 32-бит). Весь пакет переделан. Размер пакета (вместе с шапкой) для приёма идёт первым... и функция приёма сразу определяет сколько должно быть принято и не ждать таймаута.
Вообще всё это для того, что бы пакеты были идентичны как для GCC(малина 32/64) и GCC(PC 32/64), WindowsCE(VisualStudio - ARM), Windows(PC 32/64 VisualStudio). В сети много разнородных устройств... и все обмениваются между собой как напрямую, так и через сервер... не прибегая к текстовым данным. Там как картинки, так просто массивы, как команды и параметры(так же просто массивы). Вот некоторые из них: Код (C++): // #define _PKT_CMD_NOP 0x00 //пустая команда - поддкржание связи #define _PKT_CMD_RD 0x01 //чтение #define _PKT_CMD_RD_ONE 0x02 //чтение указанного параметра #define _PKT_CMD_WR 0x03 //запись #define _PKT_CMD_WR_ONE 0x04 //запись указанного параметра #define _PKT_CMD_RD_TYPE 0x05 //чтение типа данных(описание,наличие) #define _PKT_CMD_RD_VER 0x06 //чтение даты и версии сервера // коды ответа #define _ANS_OK 0x00 //нормально #define _ANS_SIZE 0x80 //ошибка размера #define _ANS_CMD 0x81 //ошибка команды #define _ANS_TYPE 0x8C //ошибка типа #define _ANS_FTYPE 0x8D //ошибка формата типа данных // PKT_TYPE #define _PKT_TYPE_NO 0x00 //нет типа - поддкржание связи #define _PKT_TYPE_SONAR 0x10 //данные сонара #define _PKT_TYPE_SERVOS_MOTOTS 0x20 //данные сервомашин и моторов #define _PKT_TYPE_VODEO 0x30 //данные видео /* **************** * ДАТА, ВЕРСИЯ * **************** */ #define _SZ_DATE_VERS 16 typedef struct { char date[_SZ_DATE_VERS]; char vers[_SZ_DATE_VERS]; } DATEVERS; /* */ typedef struct { uint64_t time; uint64_t timeclock; uint64_t oldtime; uint64_t oldtimeclock; } TIMESERVER; /* ********************* * СОНАР - ДАЛЬНОМЕР * ********************* */ // PKT_FTYPE_SONAR #define _PKT_FTYPE_SONAR 0x10 //полная структура данных #define _PKT_FTYPE_SONAR_TIME 0x11 //время #define _PKT_FTYPE_SONAR_DISTANCE 0x12 //дистанция в см. #define _PKT_FTYPE_SONAR_DIAM 0x13 //диаметр пятна typedef struct { uint64_t time; uint64_t timeclock; int16_t distance; int16_t radius; } TYPE_SONAR; /* ************************ *СЕРВОМАШИНЫ И ПРИВОДЫ * ************************ MotorsPulse - импусльс на задания моторов - если параметр задан то вырабатывается импульс движения (время в микросекундах) при установке Pulse > 0 и MotorsPulse == 0 никакой реакции моторов нет(задания моторов игнорируются), при Pulse > 0 и MotorsPulse > 0 идёт отрабока импульса временем MotorsPulse(задания моторов игнорируются), при Pulse == 0 производится обычное упраление. Значением задания моторов при отработке импульса motorsL и motorsR. */ //_PKT_FTYPE_SERVOS_MOTOTS #define _PKT_FTYPE_SERVOS_MOTOTS 0x20 //полная структура данных #define _PKT_FTYPE_SERVOS_MOTOTS_TIME 0x21 //время #define _PKT_FTYPE_SERVOS_MOTOTS_SET 0x22 //структура задания #define _PKT_FTYPE_SERVOS_MOTOTS_STAT 0x23 //структура состояния #define _PKT_FTYPE_SERVOS_MOTOTS_PCLR 0x24 //команда сброса импульса (выдаётся серверу приводами для сброса) typedef struct { uint64_t time; uint64_t timeclock; uint64_t tMotorsPulse; //импусльс на задания моторов(сбрасывается в статусе при исполнении) int16_t servoH; //горизонтальное положение головы int16_t servoV; //вертикальное положение головы int16_t motorsL; //левые колёса int16_t motorsR; //правые колёса uint8_t Pulse; //команда импульса } SERVOS_MOTORS; timeclock - изменяется источником, если "долго" не меняется, то данные не действительны.
Вот пример(выполняю на GCC Debian10): Код (C++): #include <stdio.h> #include <stdint.h> #define _sz 32 uint8_t buf[_sz]; void f1(uint8_t *buff, uint64_t par) { (*(uint64_t*)(buff)) = par; } int64_t f2(uint8_t *buff) { return (*(uint64_t*)(buff)); } int main(void) { uint64_t par = 0xF7F6F5F4F3F2F1F0; int cnt = 0; uint8_t *bbuf = &buf[5]; f1(bbuf, par); par = f2(bbuf); printf("buffer:\n"); while(cnt < _sz) { printf("%02X ", buf[cnt]); cnt++; } printf("\ntest: sz=%i val=%lli\n", sizeof(buf), par); return 0; } Ну и выполнение в консоли: Код (Text): igor@debianNUC7PJYH:~/coding/GCC/test$ ./test buffer: 00 00 00 00 00 F0 F1 F2 F3 F4 F5 F6 F7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 test: sz=32 val=-579005069656919568 igor@debianNUC7PJYH:~/coding/GCC/test$ Прокатывает... всё отлично. И на удалённом(по VPN SSH) код и результат такой же. К VisualStudio на работе доступа нет. Вот и думаю почему-то в разных средах один и тот же код (сейчас не проверю - это на работе) не совпадает
А вот тот же пример: Код (C++): #include <stdio.h> #include <stdint.h> #define _sz 32 uint8_t buf[_sz]; void f1(uint8_t *buff, uint64_t par) { (*(uint64_t*)(buff)) = par; } int64_t f2(uint8_t *buff) { return (*(uint64_t*)(buff)); } int main(void) { uint64_t par = 0xF7F6F5F4F3F2F1F0; int cnt = 0; uint8_t *bbuf = &buf[5]; f1(bbuf, par); par = f2(bbuf); printf("buffer:\n"); while(cnt < _sz) { printf("%02X ", buf[cnt]); cnt++; } printf("\ntest: sz=%i val=%lli\n", sizeof(buf), par); return 0; } Результат работы GCC Debian 10 (Linux debianNUC7PJYH 4.19.0-13-amd64 #1 SMP Debian 4.19.160-2 (2020-11-28) x86_64 GNU/Linux) Код (Text): igor@debianNUC7PJYH:~/coding/GCC/test$ ./test buffer: 00 00 00 00 00 F0 F1 F2 F3 F4 F5 F6 F7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 test: sz=32 val=-579005069656919568 igor@debianNUC7PJYH:~/coding/GCC/test$ И результат работы GCC Moxa (Linux Moxa 2.6.9-uc0 #5 Wed Jun 28 14:35:20 CST 2017 armv4tl unknown) Код (Text): www-data@Moxa:~/ramdisk$ ./test buffer: 00 00 00 00 F0 F1 F2 F3 F4 F5 F6 F7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 test: sz=32 val=-579005069656919568 www-data@Moxa:~/ramdisk$ Обратите внимание на расположение байт в массиве. Исходник Один и то же просто откомпилировано разными GCC и испытано на разных устройствах. Так что про быдлокодинг в свой адрес НЕ ПРИНИМАЮ. Я не брехун! Тот кто считает, что у него ума много, пусть смоет его в унитазе... а то воняет.
Не переживай, друже. Быдлокод - это когда быдло твой код не поняло. Поэтому больше кода хорошего и разного
Прошу прощения за резкость! Видит Бог не со зла. Но так же не видел фраз типа "Был не прав", "Беру свои слова обратно", "Извините" и прочее. Я понимаю так, что все правы... таким я думаю надо сказать: "Мама роди меня обратно", ну или исполнить,то что сказано в #71. PS Сформированный массив на одной платформе может быть не корректен при приёме его на другой.
Главным показателем говнокода является не то, что он работает с ошибками. А то, что на одной системе код работает как положено, а на другой -- не пойми как. Хотя в контексте приведённого примера, скорее всего, имеет место дефект компилятора. Разработчикам компилятора было лень писать код, который будет проверять адрес памяти и соответствующим образом генерировать машинную логику функции. Они эту работу переложили на плечи разработчиков программ на языке C. Языки C и C++ не являются кросс-платформенными языками. Поэтому, если пишите кросс-платформенный код, то нужно позаботиться о том, что бы код был корректным для разных платформ (с учётом специфики этих платформ).
Так а на что нужно обратить внимание? Все правильно, как в памяти так и в массиве. Так и должно быть.
Я не спец в ARM'ах, но поверхностный поиск выдал следующее (из документации к GCC): Код (Text): -munaligned-access -mno-unaligned-access Enables (or disables) reading and writing of 16- and 32- bit values from addresses that are not 16- or 32- bit aligned. By default unaligned access is disabled for all pre-ARMv6, all ARMv6-M and for ARMv8-M Baseline architectures, and enabled for all other architectures. If unaligned access is not enabled then words in packed data structures are accessed a byte at a time. The ARM attribute Tag_CPU_unaligned_access is set in the generated object file to either true or false, depending upon the setting of this option. If unaligned access is enabled then the preprocessor symbol __ARM_FEATURE_UNALIGNED is also defined. Igor68, Вы когда компилировали под ARM (armv4tl), указывали компилятору GCC, что Вам нужен по-байтовый доступ к памяти? Или поступали по принципу -- сделаю как-нибудь, а потом обвиню в этом компилятор.
Судя по всему, проблема в том, что человек не изучил особенности платформы, для которой пишет код. А потом начинает удивляться -- "а почему оно работает не так как я хочу!".
Игорь, уж не от меня ли вы ждете этих слов? Где и что я сказал вам неверно? не Вы ли сами три дня назад наставили мне плюсиков почти под каждым сообщением? А теперь что - передумали? свой код вот так перепишите и попробуйте: Код (C++): #include <stdio.h> #include <stdint.h> #define _sz 32 uint8_t buf[_sz]; void f1(uint8_t* buff, uint8_t* ptr) { buff = ptr; } int64_t f2(uint8_t *buff) { return *((uint64_t*)buff); } int main(void) { uint64_t par = 0xF7F6F5F4F3F2F1F0; int cnt = 0; uint8_t *bbuf = buf + 5; f1(bbuf, (uint8_t*) &par); par = f2(bbuf); printf("buffer:\n"); while(cnt < _sz) { printf("%02X ", buf[cnt]); cnt++; } printf("\ntest: sz=%i val=%lli\n", sizeof(buf), par); return 0; } При приведении типов внимательно следите, куда Вы ставите скобки. В ваших процедурах f1 f2 скобки стоят бессмысленно