И снова об указателях

Здравствуйте!
Как-то давно я нашел в интернете объемную статью от ЕвгенийП об указателях.
Ссылки, к сожалению нет, но есть конспект этой статьи.
Там написано лучше, чем в учебнике.
И вот сегодня я задался целью скопировать одну область памяти, привязанную к имени переменной, в другую область памяти.
С этой целью я разработал подпрограмму peregon.
Контрольные примеры проходят.
Вот что получилось.
Есть ли здесь “подводные камни”?
Спасибо!

void setup()
{
  float istok1 = 3.1415;
  float priem1;

  int istok2 = 12345;
  int priem2;

  peregon(&istok1, &priem1, 4); // istok1 копируется в priem1 (float)
  
  peregon(&istok2, &priem2, 2); // istok2 копируется в priem2 (int)

  Serial.begin(9600);
  Serial.println(String(priem1,4));
  Serial.println(priem2);
}

void loop()
{
}

void peregon(void *x, void *y, int z)
{

  byte* ptr1 = x;
  byte* ptr2 = y;
  for (int i = 0; i <= z - 1; i++)
  {
    *(ptr2 + i) = *(ptr1 + i);
  }
}

1 лайк

Компилируется?

Скетч использует 4420 байт…
Глобальные переменные используют 198 байт…

Да. И контрольные примеры проходят.

на мой взгляд должны быть предупреждения. Может у вас подробный вывод при компиляции не включен?

А так да, вы написали то, что уже давно существует - memcpy()

стандартом является обратный порядок операндов - сначала “куда”, а потом - “откуда”.

Но вообще молодец. Особенно если сам написал.

1 лайк

Не включен.

Я про это знаю. Но мне надо будет вместо строки 29 обчередной байт записывать в EEPROM.

Чем не устроила системная memcpy ?

Смотрите #6

Это что за хрень ?
2.
Для EEPROM есть PUT и GET …

i пробегает от 0 до z-1. Что не так?

i<z не подходит ? Зачем Вы заставляете МК на каждом проходе делать лишние вычисления ???

Спасибо за замечание. Больше не буду. Здесь речь чуть-чуть о другом идет - об указателях.

Учитывая замечания Komandir (я бы до этого не додумался), и воплощая в жизнь мою затею,получилось вот что:

#include <EEPROM.h>
void setup()
{
  float istok1 = 2.718;
  float priem1;

  int istok2 = 31987;
  int priem2;

  to_eeprom(&istok1, 0, sizeof(float));
  to_eeprom(&istok2, 4, sizeof(int));

  from_eeprom(&priem1, 0, sizeof(float));
  from_eeprom(&priem2, 4, sizeof(int));

  Serial.begin(9600);
  Serial.println(String(priem1, 4));
  Serial.println(priem2);
}

void loop()
{
}

void to_eeprom(void *x, int adress, int razmer)
{
  byte* ptr = x;
  int adr = adress;
  for (int i = 0; i < razmer; i++)
  {
    EEPROM.update(adr, *(ptr + i));
    adr++;
  }
}

void from_eeprom(void *x, int adress, int razmer)
{
  byte* ptr = x;
  int adr = adress;
  for (int i = 0; i < razmer; i++)
  {
    *(ptr + i) = EEPROM.read(adr);
    adr++;
  }
}

Ещё бы проверить работу со структурой.

А теперь откройте библиотеку EEPROM.h и посмотрите исходники метедов put() и get()

Когда то меня вот это “умиляло”.
“Умилило” настолько, что захотелось сделать проще.

float EEPROM_float_read(int addr)
{
    // чтение
    byte raw[4];
    for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i);
    float &num = (float&)raw;
    return num;
}
void EEPROM_float_write(int addr, float num)
{
    // запись
    byte raw[4];
    (float&)raw = num;
    for(byte i = 0; i < 4; i++) EEPROM.update(addr+i, raw[i]);
}

Я знаю об этих методах.
Просто захотелось научиться работать с указателями.

В ассемблере это делается проще.

если хотите еще чему-то научиться - включите подробный вывод при компиляции и исправьте все строчки кода, где компилятор дает предупреждения

А предупреждения должны быть красными?

Вот, знаете, я, наверное, тупею.

Вам это надо для упражнения или для дела? Если первое, то, конечно, упражняйтесь на здоровье, а если для дела, то, простите, чем Вас не устраивает системная функция

void eeprom_update_block (const void *__src, void *__dst, size_t __n);

Кстати, имеются соответствующие:

void eeprom_read_block (void *__dst, const void *__src, size_t __n);
void eeprom_write_block (const void *__src, void *__dst, size_t __n);

Зачем писать свою функцию, когда есть системная, которая делает то же самое, но делает это лучше (например, не забывает вызывать eeprom_busy_wait() перед каждой операцией, чего Вы не делаете принципиально)?

1 лайк

Для упражнения. Для изучения.