Ошибка программы при своевременном разыменовании 64-битного int

Мой код ведет себя странно. Следующее работает без проблем на Arduino Nano, но, похоже, дает сбой на DUE

void putData64(byte* packet, int pos, uint64_t data)
{
    uint64_t* h= (uint64_t*) (packet+pos+2);
    *h= data;
}

Проблемная строка, похоже, вторая (*h= data), поскольку ее закомментирование позволяет программе работать без проблем.

Аналогично, следующие строки вызывают проблему на DUE, но нормально работают на Nano:

char* data;
// ... данные чем-то заполнены
uint64_t* t= (uint64_t*) (data+1);
uint64_t test= *t;

Что-то мне не хватает?

, 👍1

Обсуждение

Вероятно, проблема с выравниванием памяти., @Majenko

Что ты пытаешься сделать? Если вы хотите использовать байты и указатели на байты, это нормально. Если вы хотите использовать 64-битную версию и указатели на нее, это тоже нормально. Но вы смешали эти два понятия. Зачем вам указывать на полпути к 64-битному значению? Предлагаю начать сначала., @Jot


1 ответ


Лучший ответ:

0

Я согласен с комментарием Маженко: возможно, это выравнивание памяти. проблема. Я не знаю особенностей Due, но при доступе памяти в виде блоков 32-битных слов данных на 32-битном процессоре, он может случается, что архитектура требует, чтобы слова данных были выровнены по Границы 32 бита (т.е. 4 байта). Это означает, что адрес uint32_t или uint64_t должно быть кратно 4. Может быть даже 8 для uint64_t, вам придется проверить.

Единственное решение этой проблемы — заполнить пакет побайтно:

void putData64(byte* packet, int pos, uint64_t data)
{
    union {
        uint64_t integer;
        byte bytes[8];
    } h = { .integer = data };
    for (int i = 0; i < 8; i++) {
        packet[pos+2+i] = h.bytes[i];
    }
}

Обратите внимание, что AVR (в Nano) представляет собой 8-битную архитектуру без каких-либо какие бы то ни было ограничения выравнивания.

,

Спасибо. Я знал о факте 8-битного и 32-битного. Я не пробовал ваш код, но он кажется правильным. В конце концов, трюк для меня заключался в следующем: void putData64 (пакет байт*, int pos, данные uint64_t) { uint32_t* out= (uint32_t*) (пакет+pos+2); uint32_t* in= (uint32_t*) данные; *(выход++)= *(вход++); *(выход++)= *(вход++); }, @user2912328

@ user2912328: Вы имеете в виду in = (uint32_t*) &data? Обратите внимание: хотя это и может сработать, это довольно хрупко. Если вы не сможете доказать, что packet+pos+2 _всегда_ кратен 4, существует риск того, что out окажется неправильно выровненным (и, следовательно, недействительным) указателем. Если у вас нет гарантий выравнивания packet+pos+2, единственным допустимым решением является копирование данных побайтово., @Edgar Bonet

да, вы правы по обоим пунктам. Отсутствует & и кратное 4, @user2912328