LINUX.ORG.RU

static const double в функции

 


0

2

Как избавиться от варнинга в ситуации:

typedef struct Solver_s {
    ...
} Solver;

double Solver_compute_X(Solver * self) {
    static const double alpha = sqrt(M_PI)/27.0; // <--- Warning
    static const double beta  = cos(3.0/17.0);   // <--- Warning
    ...
    return ... alpha ... beta ...;
}

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

★★★★★

старый добрый define:

#define alpha (sqrt(M_PI)/27.0)
компилер это всё равно в константу соптимизирует

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

компилер это всё равно в константу соптимизирует

А ты уверен? Результат может быть разным на разных платформах --> возьмёт и не оптимизирует. Плюс, #define - глобальный.

AlexVR ★★★★★
() автор топика
Ответ на: комментарий от AlexVR

Ставлю на то, что он одинаковый код свернет.

anonymous
()
Ответ на: комментарий от AlexVR

Чтобы такое не было соптимизированно нужно ещё постараться.

dvl36
()

Не константа, но статическая переменная вычисляемая единожды.

static double alpha = 0;
static int alpha_calculated = 0;
if (!alpha_calculated) {
    alpha = sqrt(M_PI)/27.0;
    alpha_calculated = 1;
}

Aswed ★★★★★
()
Последнее исправление: Aswed (всего исправлений: 1)
Ответ на: комментарий от Aswed

static int alpha_calculated = 0;
if (!alpha_calculated) {

убиват

anonymous
()

Warning сюда, гений. Может, он просто ругается на то, что static const - бессмысленное сочетание (и совершенно прав).

alegz ★★★★
()
Ответ на: комментарий от alegz

static const - бессмысленное сочетание (и совершенно прав)

Почему?

staseg ★★★★★
()
Ответ на: комментарий от alegz

вангую что-то типа

initializer element is not a constant expression

anonymous
()

Никак. В C нету constexpr.

anonymous
()
const double alpha = 123e456; // sqrt(foo)/bar


/thread

Gvidon ★★★★
()
Ответ на: комментарий от alegz

Warning сюда,

.../integ.c:107:33: предупреждение: initializer element is not a constant expression [по умолчанию включена]
     static const double q_z_1 = -3.0/(2.0*sqrt(M_PI));
AlexVR ★★★★★
() автор топика
Ответ на: комментарий от Cactus64k

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

Ну только clang без оптимизации оставил «callq sqrt». Но глобальный define смотрится коряво.

AlexVR ★★★★★
() автор топика
Ответ на: комментарий от AlexVR

workaround: просто убери const. Да, придется самому следить, чтобы не изменять эти «константы». Или, как советует анонимус, используй полностью вычисленное значение.

staseg ★★★★★
()
Ответ на: комментарий от AlexVR

Я иногла локальные макросы делаю так:

void foo(){
#define macro ... 
    ...
#undef macro
}

Но для эмуляции константы это все равно смотрится не очень)

staseg ★★★★★
()
Ответ на: комментарий от AlexVR

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

Cactus64k
()
Ответ на: комментарий от staseg

кстати static внутри функции - обычно зло, их надо выносить в модули. Недавно на собеседовании кто-то на этом попался :-)

MKuznetsov ★★★★★
()
Ответ на: комментарий от AlexVR

А ты уверен?

Даже современные борще-технологии это могут из коробки:

CL-USER> (defun test ()
           (cos (/ 3.0 17.0)))
TEST
CL-USER> (compile 'test)
TEST
NIL
NIL
CL-USER> (test)
0.9844694
CL-USER> (disassemble 'test)
21FEDD0A:
       0:      89E6             move  esi, esp
       2:      81CEFCFF0F00     or    esi, FFFFC
       8:      3966D0           cmp   [esi-30], esp
      11:      7310             jnb   L1
      13:      80FD00           cmpb  ch, 0
      16:      750B             jne   L1
      18:      55               push  ebp
      19:      89E5             move  ebp, esp
      21:      B853F3FE21       move  eax, 21FEF353    ; 0.9844694
      26:      FD               std   
      27:      C9               leave 
      28:      C3               ret   
L1:   29:      E8160212FE       call  2010DF42         ; #<Function RUNTIME:BAD-ARGS-OR-STACK 2010DF42>
NIL
Oxdeadbeef ★★★
()

Остановился на:

double Solver_compute_X(Solver * self) {
    const double alpha = sqrt(M_PI)/27.0;
    const double beta  = cos(3.0/17.0);
    ...
    return ... alpha ... beta ...;
}

Для меня более читабельно, а вычисления корня делает только clang без ключей оптимизации.

AlexVR ★★★★★
() автор топика
Ответ на: комментарий от MKuznetsov

кстати static внутри функции - обычно зло, их надо выносить в модули

это пуркуа? для постоянных флагов - самое оно

ananas ★★★★★
()
Ответ на: комментарий от Aswed

Не константа, но статическая переменная вычисляемая единожды.

И в итоге имеет три условия - два на каждый static и один явный if(!alpha_calculated).

andreyu ★★★★★
()
Ответ на: комментарий от DarkEld3r

Почему?

Потому, что на каждый статик сгенерится неявный if().

andreyu ★★★★★
()
Ответ на: комментарий от staseg

А в чем зло кроме проблем с многопоточностью?

проще проиллюстрировать, чем объяснить :-) объявляя static внутри функции ты зачем-то просто прячешь (на самом деле глобальную) переменную внутри scope функции. Чем порождаешь больше проблем, чем получаешь пользы.

// все состояния объявляются и видны в начале файла/модуля
// проще отлаживать, и поддерживать код 
static int foo_state=0; 
 
// можно инициализовать состояние до вызова
// и не городить if (!foo_state) { initialize } в каждом вызове
//
__attribute__((constructor)) static void prepare_foo() {
   foo_state=....
};

// можно разделять состояние с другими функциями
int odd_foo();
int even_foo();
int foo() {
...
}

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

// можно инициализовать состояние до вызова

И поиметь пару часов веселья в отладчике, когда наткнёшься на неопределённый порядок вызовов между разными единицами трансляции.

// можно разделять состояние с другими функциями

Будто что-то хорошее.

Gvidon ★★★★
()
Ответ на: комментарий от Gvidon

И поиметь пару часов веселья в отладчике, когда наткнёшься на неопределённый порядок вызовов между разными единицами трансляции.

если важен порядок - делай порядок :-) пиши и вызывай сам конструкторы в нужной последовательности. Это-ж всё-таки «C» :-)

можно разделять состояние с другими функциями

Будто что-то хорошее.

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

int odd_foo();
int even_foo();
int foo() {
    ...
    if (some_condition) odd_foo();
    else even_foo();
}

MKuznetsov ★★★★★
()
Ответ на: комментарий от staseg

А в чем зло кроме проблем с многопоточностью?

ещё небольшая иллюстрация. На плюсах следующий код будет считаться уродством и издевательством над сотоварищами:

class A {
  ...
  int foo() {
     static int foo_state=0; // <-- WTF?
     ...
  } 
};
так вот в обычном «C» то-же самое :-)

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

То есть проблемы не технические, а скорее организационные, и наверное во многом с уклоном на будущее развитие.

staseg ★★★★★
()
Ответ на: комментарий от MKuznetsov

Да, в методе хранить состояние некомильфо, это понятно :)

staseg ★★★★★
()
Ответ на: комментарий от MKuznetsov

А в чем зло кроме проблем с многопоточностью?

Чем порождаешь больше проблем, чем получаешь пользы.

Емкий ответ на вопрос.

andreyu ★★★★★
()
Ответ на: комментарий от AlexVR

Выше соватовали убрать static из объявления переменной. Тоже склоняюсь к этому варианту. Обычно такие стандартные варнинги разобраны уже десять раз на переполнениестека.ком

Cactus64k
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.