vitus_wagner: My photo 2005 (Default)
[personal profile] vitus_wagner
Вот такую странную картину я тут наблюдаю:

Debian testing, gcc 8.2.0. Имеется вот такой C-шный код:
static void log (int elevel,  const char *fmt, va_list args)
{
 bool write_to_file, write_to_stderr, write_somewhere_else;
 va_list error_args, std_args;
.... здесь вычисляем куда надо писать
if (write_to_file && write_to_stderr) 
  va_copy(std_args,args);

.... некоторое количество кода, заведомо не меняющего флагов write_to
if (write_to_file) {
   vfprintf(f,fmt, args);
}
if (write_to_stderr) {
   if (write_to_file) {
      vfprintf(stderr, fmt, std_args);
   } else {
      vfprintf(stderr,fmt,args);
   }
   ffush(stderr);
}


В 64-битной системе компилятор кушает этот код без вопросов. В 32-битной ругается

error: ‘std_args’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
vfprintf(stderr, fmt, std_args);

Нет, я понимаю, что макросы для va_* могут быть реализованы по разному в зависимости от архитектуры процессора, но не до такой же степени...

Date: 2018-12-09 06:59 pm (UTC)
livelight: (Default)
From: [personal profile] livelight
Это компилятору надо догадаться, что условие
if (write_to_stderr) {
   if (write_to_file) {

эквивалентно условию
if (write_to_file && write_to_stderr)


А это, кроме всего прочего, ещё и другой порядок аргументов в короткой конъюнкции.

Date: 2018-12-09 07:35 pm (UTC)
livelight: (Default)
From: [personal profile] livelight
Я бы на месте даже не компиляторов, а программистов, ругался во всех архитектурах. Даже после понимания про тождественность логических условий. Ибо что такое этот va_copy? Ну, допустим, в какой-то архитектуре повезло, и это явное копирование. Но я бы на всякий случай предполагал, что это, как и в большинстве Си-шных конструкци такого рода, - просто вызов некой функции, которой передают указатели на оба аргумента. Однако, передача в какую-то функцию указателя на локальную переменную - ещё не повод считать эту переменную инициализированной.

Date: 2018-12-10 08:44 am (UTC)
livelight: (Default)
From: [personal profile] livelight
Я даже как-то писал код без break перед default.
Но по-хорошему, конечно, надо там вместо брейка ставить какую-то конструкцию, однозначно понимаемую и человеком, и компилятором, что брейк здесь пропущен умышленно. Вроде, в C# так и сделали.

Date: 2018-12-10 09:05 am (UTC)
livelight: (Default)
From: [personal profile] livelight
Именно в таком виде я его не видел ни разу (видел только примерно такой, с точностью до регистра), так что не уверен в степени его стандартности и общепризнанности.

Date: 2018-12-10 05:22 am (UTC)
From: [personal profile] qwe_rty
Компилятор не обязан заниматься условным протаскиванием присваиваний. Никакой стандарт от него этого не требует, хотя и не запрещает заниматься какими угодно оптимизациями. Правильно было бы вынести va_copy из-под условия. Если компилятор умный, он убъет это присваивание как мертвый код.

Date: 2018-12-10 08:40 am (UTC)
livelight: (Default)
From: [personal profile] livelight
Ну он же сказал: возможно неинициализированная. Ну недопёр, бывает. Он обязан, конечно, но, как строго доказано, на любой умный компилятор можно найти текст программы, в котором он некоторые свойства не сможет распознать.
А бывают ещё случаи, когда переменная заведомо неинициализированная.

Date: 2018-12-10 09:19 am (UTC)
From: [personal profile] qwe_rty
Ничего подобного. Это сообщение означает, что переменная, возможно, не инициализирована, а не что она обязательно не инициализирована. В общем случае к другому не сводимо. Из современных компиляторов немногие протягивают присваивания условно. Это непросто.

Date: 2018-12-10 08:31 pm (UTC)
From: [personal profile] qwe_rty
Вообще, компилятор обязан заниматься только тем, что указано в стандарте языка. Хороший компилятор, конечно, обычно делает больше. У разных компиляторов это больше разное, к тому же меняется версия от версии. В данном случае правильно было бы вынести вызов va_copy из-под условия. Компилятор перестанет ругаться, исходники станут проще, порожденный код вряд ли станет длиннее или медленнее, скорее наоборот.

Date: 2018-12-10 07:09 am (UTC)
qkowlew: На Зилантконе меня сфоткали мыльницей. Мыльницам не позирую! (Default)
From: [personal profile] qkowlew
Может быть разница в реализации макросов.
У меня было как-то ещё в эпоху PDP-11 и "Ленинградского Си" анекдотическое.

if (условие) функция();

компилировалось в какой-то махровый бред, ибо функция была на самом деле чуть криво написанным макросом, результат раскрытия которого частично "выпадал" из блока условия.

if (условие) { функция(); }

компилировалось как ожидалось и работало правильно.

Date: 2018-12-10 09:04 am (UTC)
livelight: (Default)
From: [personal profile] livelight
А вот тех, кто пишет такой развесистый макрос, не окружив его собственными скобками соответствующей формы, надо бить канделябрами.

Date: 2018-12-10 10:14 am (UTC)
livelight: (Default)
From: [personal profile] livelight
Раз ручное окружение вызова макроса фигурными скобками помогает - значит, макрос обязан сам в себя включать эти фигурные скобки, чтобы гарантированно сохранять синтаксическую целостность своего тела.

К счастью, конфликтов, когда в одних контекстах надо бы окружать фигурными скобками, а в других - круглыми, в Си не бывает. По крайней мере, я таких примеров не встречал.

Date: 2018-12-10 10:19 am (UTC)
livelight: (serenity)
From: [personal profile] livelight
А ещё в куковлевском примере с финальным ";" могут быть проблемы, если после if с макросом идёт else. Вот эта болезнь языка препроцессора не имеет хорошего лекарства, кроме опять же ручного окружения if-блока и else-блока в собственные фигурные скобки.

Ну и вообще врождённых болезней у языка препроцессора много :)

Date: 2018-12-10 10:54 am (UTC)
yurikhan: (Default)
From: [personal profile] yurikhan

Ну каноническое решение против else выглядит как

#define DO_SOMETHING(x) \
    do { \
        do_something_one(x); \
        do_something_two(x); \
    } while (0)

// …

if (condition)
    DO_SOMETHING(y);
else
    do_something_three(y);

Date: 2018-12-10 11:01 am (UTC)
livelight: (Default)
From: [personal profile] livelight
Точно, было такое лекарство. Хотя назвать его "хорошим" язык не поворачивается :)

Date: 2018-12-10 11:06 am (UTC)
yurikhan: (Default)
From: [personal profile] yurikhan
Ну, оно невкусное, да. В общем-то как и большинство лекарств.

Date: 2018-12-11 02:35 am (UTC)
From: [personal profile] zevaka_derevnia
Вот - только хотел написать. Старое и давно известное средство.

Date: 2018-12-10 07:16 am (UTC)
qkowlew: На Зилантконе меня сфоткали мыльницей. Мыльницам не позирую! (Default)
From: [personal profile] qkowlew
А наиболее вероятная архитектурная разница - в размерности указателей всё-таки.

Примерно как в Турбо Си 2.0 было две хорошо применяемых модели памяти - Tiny и Huge.

в первой указатели были 16-битные, и результат собирался в .com файл.
во второй указатели были кривые интеловские, но арифметика их РАБОТАЛА КОРРЕКТНО.

Попытки компилить РАБОТАЮЩИЙ в Tiny и Huge код в прочих моделях памяти (Small и Large) рано или поздно приводили к сегфолтам и к иным странным результатам.
Edited Date: 2018-12-10 07:17 am (UTC)

Profile

vitus_wagner: My photo 2005 (Default)
vitus_wagner

June 2025

S M T W T F S
1 23 4 56 7
89 1011121314
15161718192021
22232425262728
2930     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 12th, 2025 08:39 am
Powered by Dreamwidth Studios