Как работает данный код

видимо в прогмем только указатели, а строки в памяти

я всегда использую только второй вариант и код работает именно так, как предполагаю.
А первая запись мне интуитивно не нравится, когда вижу в чьем-то коде - передергивает слегка :slight_smile:

Да это, вроде, с одной стороны объяснимо - разные адресные пространства и оба могут, в теории, начинаться с нуля.

Но простой тест показал, что строка при такой записи всё равно уходит в RAM:

void setup() {
  Serial.begin(115200);

  const char * yin  PROGMEM = "789";
  const char * yang PROGMEM = "123456789";
  const char * dao  PROGMEM = "456789";

  Serial.print("*yin  = 0x"); Serial.println((uint16_t) yin, HEX);
  Serial.print("*yang = 0x"); Serial.println((uint16_t) yang, HEX);
  Serial.print("*dao  = 0x"); Serial.println((uint16_t) dao, HEX);

  while (*dao) {
    Serial.print((char) *dao);
    dao++;
  }
}

void loop (void) {}

Вобщем, потыкался и так и сяк - не выходит.

И не соображу, как раскладку по памяти посмотреть - avr-objdump -Ы мне что-то у elf-a не показывает секцию .progmem

Дак правильно, при таком обьявлении сама строка остается в ОЗУ, а в прогмем ты пхаешь указатель на неё. :slight_smile:

1 лайк

Ну, можно же было помечтать…

Порылся в литературе, получается что эти две записи абсолютно эквивалентны для компилятора.
Однако я так понял, что первая более информативна в исходном коде, поскольку прямо указывает читателю (не компилятору, а читателю!), что функция работает не просто с указателем на единичную переменную, а с массивом

как сказать, я б подумал, что компилятор весь массив в стэк загоняет, чтобы функции передать. Поэтому стараюсь явно указатели указывать.

Да, господь с Вами!

Компилятору лишние контакты с ФСКН ни к чему.

1 лайк

не знал, спасибо.

а вот так:
void foo(“abcd”) ;
аналогично указатель передается?

Конечно.

1 лайк

Евгений, а еще вопрос
Правильно я понял, что при передаче размерного массива цифра размера ни на что не влияет?

void foo(char arr[10]) ;

Больше того, если в функции нужно размер массива узнать, то этот самый размер нужно вторым параметром передавать.

Влияет. Если указана, то в функции можно брать sizeof, например.

В обычных функциях это не слишком важно, а вот в шаблонных - очень важно. Шаблон, он ведь генерирует функцию с типом параметра ,точно совпадающим с типом переданного аргумента. Поэтому, смотрите, функция из EEPROM.h

template< typename T > T &get( int idx, T &t ){
    EEPtr e = idx;
    uint8_t *ptr = (uint8_t*) &t;
    for( int count = sizeof(T) ; count ; --count, ++e )  *ptr++ = *e;
    return t;
}

ей можно передавать массивы и она отлично будет работать. Но именно массивы, а не указатели. Например:

//
// Правильно - тип второго параметра будет long [10] 
// и get честно прочитает 40 байтов
//
long kaka[10];
...
get(eepAddr, kaka);

//
// Неправильно - тип второго параметра будет long *
// и get прочитает 2 байта
//
long * kaka = new long[10];
...
get(eepAddr, kaka);

Понятна разница?

Извините , это был не вопрос, просто проинформировал , что при такой попытки компилятор ругнулся , но после перегрузки иде все заработало. Поэтому уточнять какая ошибка вроде как небыло смысла(ответ то не нужен был ) А вобще я нашел в логах - warning: initializer-string for array of chars is too long [-fpermissive] , вот так он ругнулся на конструкцию

char TBuf[] = “000”;

Но как я говорил после перезагрузки глюк исчез…

Всем большое спасибо. частично с указателями разобрался ,а также наконец дошла мотивациея компилятора при обьеденении…
код работает нормально и вроде даже как самый наименьший по обьему в во флеш и рам…(из тех что мог придумать)

На такую строку он не мог так ругаться. Вот, если там у Вас между [ и ] была цифирь (например, 1 или 0), тогда да. Т.е. исчез он после того, как там цифирь исчезла. Я уж не говорю, что у Вас сейчас кавычки неправильные. Это ещё раз о том, что только копипаст!

Евгений Петрович, при всем уважении вы отвечали не на тот вопрос, что был задан (не исключаю и мою ошибку понимания вопроса). Но все же в функцию передастся указатель на массив символов, а не сам массив.

но тип этого указателя будет зависеть от цифр размера в квадратных скобках

То есть тип char [0] будет отличаться от char [10]? Почему?
Указатель указывает на начало области памяти, а что там дальше - решает программист. Разве нет?

Насколько я понимаю, в случае описания процедуры с явным указанием размера вы заранее сообщаете компилятору, что будете передать в процедуру именно массив размером 10, а не 2, к примеру. И эту информацию можно использовать, например для выделения памяти для временного буфера.

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

int bb[2];

int foo(int aa[10]) {
  return aa[8];
}

void loop() {
 Serial.println(foo(bb));
}

А такой что говорит?