Перейти к содержанию
    

Компилятор IAR 8.5 Си не дает ошибку

On 10/15/2023 at 5:56 PM, jcxz said:

Вроде как там всего одна строка. Так как символ '\' - указывает, что это единая строка. После макроподстановки получится одна строка кода.

Понятно.

Спасибо !

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, repstosw сказал:

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

Это да... Но я имел в виду вот так

func() {
  c->luma_buffer = ve_malloc(c->input_buffer_size);

  if(c->luma_buffer == NULL)
    goto nomem;
  else {
    c->bytestream_buffer_size = 3 /*1*/ * 1024 * 1024;
    c->bytestream_buffer      = ve_malloc(c->bytestream_buffer_size);
    
    if(c->bytestream_buffer == NULL)
      goto nomem;
    else {
      unsigned int luma_size   = ALIGN(c->mb_width * 16, 32) * ALIGN(c->mb_height * 16, 32);
      unsigned int chroma_size = ALIGN(c->mb_width * 16, 32) * ALIGN(c->mb_height *  8, 32);

      //...
    }
  }

  nomem:
  printf("no mem. bye-bye...\n");

  return;
}

 

1 час назад, dimka76 сказал:

Чего нет?

Того и нет, что макрос __LINE__ развернется на этапе подстановки в строке вызова, по правилам разворачивания макросов.
Вы предполагаете, что TTT() сначала развернется в то, что написано в TTT, а __LINE__ заполнится "по мере парсинга", но это не так.
Препроцессор Си таким образом защищается от рекурсивных вызовов внутри макроса того же макроса (если не понятно, пишите).
 

45 минут назад, jcxz сказал:

Вроде как там всего одна строка. Так как символ '\' - указывает, что это единая строка. После макроподстановки получится одна строка кода.

Ды не, это тут даже не важно. На момент разворачивания TTT() __LINE__ не используется в макрос-операции # или ##, поэтому __LINE__ развернется ровно 1 раз.
 

1 час назад, jcxz сказал:

Почему? Вроде всё ок. Разве что __packed должен быть перед struct (хотя не уверен что это важно).

В структуре все элементы u32 имеют естественное выравнивание в 4 байта, поэтому дописывать упаковку нет смысла, да и весьма чревато: помимо потенциально "опасных" невыровненных (а потому - неатомарных) чтений volatile, в структуре могли оказаться, например, 8 или 16-битные регистры, выровненные по границе 4 байт. И с __packed получилась бы неправильная каша:

// должно было быть:
// 0x0 -  8-разрядный регистр a
// 0x4 - 16-разрядный регистр b
// 0x8 - 32-разрядный регистр c

// с __packed будет так
__packed struct NoValidMMIO {
  __IO u8  a; // реальное смещение 0x0
  __IO u16 b; // реальное смещение 0x1 <<-- ERROR
  __IO u32 c; // реальное смещение 0x3 <<-- ERROR
};

// без __packed будет правильно
struct ValidMMIO {
  __IO u8  a; // реальное смещение 0x0
  __IO u16 b; // реальное смещение 0x4 <<-- OK
  __IO u32 c; // реальное смещение 0x8 <<-- OK
};

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

39 минут назад, Arlleex сказал:

Ды не, это тут даже не важно. На момент разворачивания TTT() __LINE__ не используется в макрос-операции # или ##, поэтому __LINE__ развернется ровно 1 раз.

Почему думаете что "не используется"? Логично предположить, что внутри concat2() как раз есть склейка ##.

39 минут назад, Arlleex сказал:

В структуре все элементы u32 имеют естественное выравнивание в 4 байта, поэтому дописывать упаковку нет смысла

Почему Вы всё время упираете на "упаковку"? Причём тут какая-то "упаковка" если в той структуре нет никаких padding?

Упаковка там вовсе не причём, а __packed - совсем для иного: Для того, чтобы указать компилятору, что структура может лежать по невыровненному адресу (по адресу, не выровненному на величину выравнивания структуры).

Я уже выше писал, что __packed используется не только для упаковки структур. Вы видимо не обратили внимание:

4 часа назад, jcxz сказал:
__packed uint x1;

__packed struct T1 {
  char y1;
  uint y2;
  char y3;
};

Здесь представлены 2 предназначения __packed.

И __packed здесь запрещает на Cortex-M для доступа к x1 использовать инструкции CPU, не поддерживающие невыровненный доступ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

57 минут назад, jcxz сказал:

Почему думаете что "не используется"? Логично предположить, что внутри concat2() как раз есть склейка ##.

Макрос раскрывается сразу, если он не участвует напрямую в операциях # или ##. В concat2() не напрямую склеиваются токены, а вызывается _concat2(a, b), который уже и разворачивается в a##b. Это - не одно и то же:

Цитата

6.10.3.1 Argument substitution

After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

Единственное, не совсем понятно, касается ли это не function-like макросов.
 

Цитата

Для того, чтобы указать компилятору, что структура может лежать по невыровненному адресу (по адресу, не выровненному на величину выравнивания структуры).

Крайне необычно и противоестественно видеть структуру MMIO-регистров периферии невыровненной.
 

Цитата

Почему Вы всё время упираете на "упаковку"? Причём тут какая-то "упаковка" если в той структуре нет никаких padding?

Потому что "упаковка" намекает как раз на то, что данные внутри структуры могут не иметь естественных выравниваний.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 часов назад, repstosw сказал:

Не нравится объявление переменных после условия.  Пока сделал объявление переменных в начале.

Объявлять переменные в начале функции(блока) - это требование классического С. Только плюсы позволяют объявлять переменные где вздумается по мере необходимости. А то, что GCC проглатывает - так это, наверняка, от ключей зависит. Указать строгую проверку на соответствие С-98, и получите тот же набор предупреждений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Edit2007 сказал:

Объявлять переменные в начале функции(блока) - это требование классического С. Только плюсы позволяют объявлять переменные где вздумается по мере необходимости.

В стандарте языка C от 89 года нету требования объявлять переменные в начале блока. Такое требование было в K&R C, еще до введения стандарта. Так что не только лишь плюсы...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Edit2007 сказал:

Объявлять переменные в начале функции(блока) - это требование классического С.

Не было такого требования. А зачастую когда в длинной функции все переменные свалены наверху - получается малопонятная каша.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, Сергей Борщ сказал:

В стандарте языка C от 89 года нету требования объявлять переменные в начале блока. Такое требование было в K&R C, еще до введения стандарта. Так что не только лишь плюсы...

В классическом C все переменные объявляли в начале блока для того, чтобы внутри блока goto пользоваться :). Потому что как только goto перескочит через объявление переменной - быть ошибке.
Но если посмотреть на ассемблерный листинг компилятора, то там всё равно место для всех локальных переменных выделятся на стеке в начале блока.

А если что и хорошо, то это декларация переменной цикла внутри оператора for. Сильно это мне нравится, особенно когда в качестве такой переменной компилятор использует регистр.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Xenia сказал:

Потому что как только goto перескочит через объявление переменной - быть ошибке.

Объявление тут как раз не шибко важно - важно определение с инициализацией.
Вот если проскочит инициализацию - тогда будет ошибка/предупреждение. Вроде, так🙂
 

Цитата

Но если посмотреть на ассемблерный листинг компилятора, то там всё равно место для всех локальных переменных выделятся на стеке в начале блока.

А Вы чей листинг смотрели? Какого CPU? Потому как именно выделение места на стеке (команды изменения SP) - зачастую в начале функции, не важно, сколько в ней будет блоков (составных операторов) со своими локальными переменными... Однако все это весьма сильно зависит от принятого соглашения по ABI.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...