Общий размер структуры

Тема в разделе "ESP8266, ESP32", создана пользователем AlexVS, 16 июн 2020.

  1. parovoZZ

    parovoZZ Гуру

    а разве компилятор это не может вычислить статически? Ведь все адрес известны на стадии компиляции.
     
  2. Igor68

    Igor68 Гуру

    В Keil - результат компиляции в листинге с выводом на Ассемблере.
    Тестовый код на ADuC7024(ядро ARM7TDMI), без заливки в контроллер. Keil uVision4.
     
    Последнее редактирование: 16 дек 2020
  3. Igor68

    Igor68 Гуру

    В принципе может с оптимизацией, но конструкция типа:
    Код (C++):

    uint8_t *b = buff + 3;
     
    предполагает, что вместо тройки может быть вообще переменная, а не константа, потому как есть операция сложения.
    В целях оптимизации кода, и если это не переменная, то компилятор "натравливается" для получения сразу адреса.
    А в конструкции:
    Код (C++):

    uint8_t *b = &buff[3];
     
    "натравливать" не надо, конечно если это константа - та самая тройка. Но если это переменная то как и в предыдущем случае и с точки зрения Ассеблера они будут идентичны.
     
    Последнее редактирование: 16 дек 2020
  4. parovoZZ

    parovoZZ Гуру

    я про что и говорю - из такой записи абсолютно не очевидно, что buff - это массив. А запись:
    Код (C++):
    uint8_t *b = &buff[3];
    абсолютно однозначна.
     
    Igor68 нравится это.
  5. SergeiL

    SergeiL Оракул Модератор

    Я проверял на древнем 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
     
     
  6. Igor68

    Igor68 Гуру

    Поздравляю! Умный компилятор! Не "натравливали" его на оптимизацию? Говорил про это в #63
    кстати если не сложно (вы пользуетесь x86) проверьте:
    Код (C++):
    uint64_t TS;
    TS = (*(uint64_t*)(&buff[3]));
    Меня интересует "выравнивание" (это не по этой теме) как 32/64 битных системах и 8 битных (ардуино).
    Будет ли необходимо выравнивание для 8-ми битных. Ардуины(IDE) под рукой нету(она на малине и запускать долго - в устройстве на колёсах). Для int64_t на ардуине обязательно выравнивать кратно 8 байт??? Если не затруднит дайте знать.
    Спасибо!
     
    Последнее редактирование: 17 дек 2020
  7. SergeiL

    SergeiL Оракул Модератор

    Оптимизация по умолчанию. Дополнительно не задавал.
    В нем 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>
     
  8. Igor68

    Igor68 Гуру

    можно и с 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-бит).
    Весь пакет переделан. Размер пакета (вместе с шапкой) для приёма идёт первым... и функция приёма сразу определяет сколько должно быть принято и не ждать таймаута.
     
    Последнее редактирование: 17 дек 2020
  9. Igor68

    Igor68 Гуру

    Вообще всё это для того, что бы пакеты были идентичны как для 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 - изменяется источником, если "долго" не меняется, то данные не действительны.
     
  10. Igor68

    Igor68 Гуру

    Вот пример(выполняю на 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 на работе доступа нет.
    Вот и думаю почему-то в разных средах один и тот же код (сейчас не проверю - это на работе) не совпадает
     
    Последнее редактирование: 17 дек 2020
  11. Igor68

    Igor68 Гуру

    А вот тот же пример:
    Код (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 и испытано на разных устройствах. Так что про быдлокодинг в свой адрес НЕ ПРИНИМАЮ. Я не брехун!
    Тот кто считает, что у него ума много, пусть смоет его в унитазе... а то воняет.
     
    parovoZZ и ИгорьК нравится это.
  12. ИгорьК

    ИгорьК Гуру

    Не переживай, друже. Быдлокод - это когда быдло твой код не поняло. Поэтому больше кода хорошего и разного :)
     
    Igor68 и parovoZZ нравится это.
  13. Igor68

    Igor68 Гуру

    Прошу прощения за резкость! Видит Бог не со зла. Но так же не видел фраз типа "Был не прав", "Беру свои слова обратно", "Извините" и прочее. Я понимаю так, что все правы... таким я думаю надо сказать: "Мама роди меня обратно", ну или исполнить,то что сказано в #71.

    PS Сформированный массив на одной платформе может быть не корректен при приёме его на другой.
     
  14. AlexU

    AlexU Гуру

    Главным показателем говнокода является не то, что он работает с ошибками. А то, что на одной системе код работает как положено, а на другой -- не пойми как.

    Хотя в контексте приведённого примера, скорее всего, имеет место дефект компилятора. Разработчикам компилятора было лень писать код, который будет проверять адрес памяти и соответствующим образом генерировать машинную логику функции. Они эту работу переложили на плечи разработчиков программ на языке C.

    Языки C и C++ не являются кросс-платформенными языками. Поэтому, если пишите кросс-платформенный код, то нужно позаботиться о том, что бы код был корректным для разных платформ (с учётом специфики этих платформ).
     
  15. ИгорьК

    ИгорьК Гуру

    upload_2020-12-18_11-3-36.png

    Судя по всему, проблема заключается не в коде, а в критиках.
     
    Igor68 нравится это.
  16. SergeiL

    SergeiL Оракул Модератор

    Так а на что нужно обратить внимание?
    Все правильно, как в памяти так и в массиве. Так и должно быть.
     
  17. AlexU

    AlexU Гуру

    Я не спец в 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, что Вам нужен по-байтовый доступ к памяти?
    Или поступали по принципу -- сделаю как-нибудь, а потом обвиню в этом компилятор.
     
    Igor68 и parovoZZ нравится это.
  18. AlexU

    AlexU Гуру

    Судя по всему, проблема в том, что человек не изучил особенности платформы, для которой пишет код. А потом начинает удивляться -- "а почему оно работает не так как я хочу!".
     
    Igor68 нравится это.
  19. AlexU

    AlexU Гуру

    В общем, я поторопился, когда написал:
    "Дело было не в бобине ...."
     
    Igor68 нравится это.
  20. b707

    b707 Гуру

    Игорь, уж не от меня ли вы ждете этих слов? Где и что я сказал вам неверно?
    не Вы ли сами три дня назад наставили мне плюсиков почти под каждым сообщением?
    А теперь что - передумали?

    свой код вот так перепишите и попробуйте:
    Код (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 скобки стоят бессмысленно