LINUX.ORG.RU

Глюк с инициализацией глобальных переменных (C/mingw)

 , , , ,


0

3

Всех приветствую!

Обнаружилось непонятное явление: после компиляции mingw32 и запуска под wine в программе не инициализируются глобальные переменные.

Более подробно:

Глобальные переменные:

bool line_mode = false;
enum {ORTHOGRAPHIC=0, PERSPECTIVE};
int projection_type=ORTHOGRAPHIC;

Некоторые ф-ции:

void reshape_cb (int w, int h)
{
    glViewport ( 0, 0, (GLint) w, (GLint) h ) ;
    WIDTH = w;
    HEIGHT = h;

       
    printf("projection_type = %d\n", projection_type);
    printf("line_mode = %d\n", line_mode);
    switch ( projection_type )
    {
      case PERSPECTIVE:
        printf("PERSPECTIVE\n");
        ...        
        break;

      case ORTHOGRAPHIC:
        printf("ORTHOGRAPHIC\n");
        ...
        break;
    };

    ...
    CHECK_GL_ERROR(); 
    printf("reshape()\n");
}
void keyboard_cb ( unsigned char key, int x, int y )
{
    switch ( key )
    {
      case 'l' :
      case 'L' :
      {
          line_mode = !line_mode;
          break;
      }

      case '1' :
      {
          projection_type = ORTHOGRAPHIC;
          reshape_cb(WIDTH, HEIGHT);
          break;
      }

      case '2' :
      {
          projection_type = PERSPECTIVE;
          reshape_cb(WIDTH, HEIGHT);
          break;
      }

      ...

    };

    glutPostRedisplay();
}

После запуска wine program.exe на экран выдается

projection_type = -1122261533
line_mode = 100
reshape()

При компиляции gcc все нормально:

projection_type = 0
line_mode = 0
ORTHOGRAPHIC
reshape()

Лечится это явление добавлением static:

static bool line_mode = false;
enum {ORTHOGRAPHIC=0, PERSPECTIVE};
static int projection_type=ORTHOGRAPHIC;

(или, возможно, инициализацией в ф-ции main) Тогда правильно работает и после mingw.

Кто-нибудь сталкивался с таким явлением? Почему это происходит?

Добавление.

Если после запуска wine program.exe нажать клавишу [2], то

projection_type = -1122261533
line_mode = 100
reshape()
НАЖАТИЕ КЛАВИШИ [2]
projection_type = 1
line_mode = 100
PERSPECTIVE
reshape()

видно значение projection_type инициализировалось как и задумано.

Тоже самое после gcc: ./program

projection_type = 0
line_mode = 0
ORTHOGRAPHIC
reshape()
НАЖАТИЕ КЛАВИШИ [2]
projection_type = 1
line_mode = 0
PERSPECTIVE
reshape()

PS Заранее благодарю за осмысленные ответы.

PS2 К сожалению, сделать маленький пример на выдачу этой ошибки пока не удалось. А вываливать кучу файлов сюда неуместно. Могу exe-шник дать для анализа явления.



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

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

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

про mingw не знаю. не использовал никогда.

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

alysnix ★★★
()

Файл всего один? Нет других файлов где те же переменные объявлены без инициализаторов? Сделай минимальный пример.

Если всё так то ты нашёл баг в mingw значит и надо его репортить. Но сначала надо убедиться что всё так.

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

Собирается строкой

x86_64-w64-mingw32.static-gcc -std=c11 common.h color.h dict.h dict.c utils.h utils.c mlib.h mlib.c glsl_prog.h glsl_prog.c glutils.h glutils.c  plane.h plane.c objmesh.h objmesh.c perlin.h noise_tex3D.h noise_tex3D.c arrstr.h arrstr.c errshow.h errshow.c  program.c -D FREEGLUT_STATIC -D GLEW_STATIC -o program.exe -static-libgcc -L/home/bark/mxe/usr/x86_64-w64-mingw32.static/lib -lglut -lopengl32 -lglu32 -lglew32s -lwinmm -lgdi32
Gyros
() автор топика
Ответ на: комментарий от Gyros

Вообще все хедеры (не компилировать)?

хидеры инклудят в единицы компиляции(*.c) или другие хидеры. сами хидеры не компилируют. это просто набор деклараций, нужных для компиляции программных файлов.

если ты этого не понимаешь, значит напорол чета там. си это тебе не пытон какой-нить

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

Это ф-ция обратного вызова

int main(int argc, char **argv)
{
  // Инициализация freeGLUT
  glutInit(&argc, argv);

  ...

  // Регистрация функций 
  glutReshapeFunc  (      reshape_cb );
  glutDisplayFunc  (      display_cb );
  glutKeyboardFunc (     keyboard_cb );
  ...

  // Основной цикл GLUT
  glutMainLoop();

  return EXIT_SUCCESS;
}   

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

grep -RF «bool line_mode» выдал

program.c:bool line_mode = false;
testglob.c:bool line_mode = false;

В testglob.c я пытаюсь такую ситуацию создать на более мелком примере; он не исп. при компиляции проблемной программы

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

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

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

Хорошо. Отпишусь позже. У меня обычно все

  • объявления констант
  • структуры
  • инлайн-ф-ции идут в хедерах.

c-файлы подключают хедеры и реализуют объявленные ф-ции Или же может быть включение h-файла в др. h-файл или c-файл, если что-то используется из него. Все обычно.

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

в хидерах должны быть только декларации обьектов, которые ты будешь использовать в нескольких «модулях». вообще то в си нет модулей. в си(и канонических плюсах) ОДИН модуль, просто разделенный на несколько файлов - «единиц компиляции» (compilation unit). а хидеры лишь помогают эти единицы правильно написать.

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

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

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

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

тогда зачем убирать хидеры, если тому нет обьяснений? :)

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

Насувай printf-ов её в разные места по ходу выполнения кода и найдёшь в каком месте она портится.

это только у дурачков прога вдруг портится и это надо ловить принтами, рассованными по всему коду. надавай ему еще советов

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

ловить надо мозгами а не дампами. дампы - это средство последней надежды.

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

в москве похоже поотрубали инет прям кусками, я не вижу доки по глутам твоим.

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

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

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

Показал 0 после mingw, как и должно быть. Странно. Вроде у меня больше нигде такой переменной нет

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

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

тогда компилятор не хочет инициализировать их по какой-то причине в целях оптимизации.

бред

просто от необдуманной+многократной компиляции .h, у него static int prоjection_type несколько штук получилось, по одной на каждый .o и очевидно не только их. И к вызову xxx_cb() всё уже упахалось

выход: писать нормальный Makefile. По крайней мере :-) и не пихать непосредственно *.h в компиляцию. И не объявлять переменные в *.h. И выучить С.

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

это cmake список сорцов для хз чего. вопрос тут - а что делает cmake, если видит хидер в списке? он запросто может его не включать в вызов билда.

cmake вообще-то генерит скрипт для gnu make или ninja, сам он не билдит вообще.

опять же хидер вообще не обязан быть компилируемым вне включения куда либо. то есть при определенном соглашении, можно и хидеры писать как раздельно компилируемые, но это будет лишь соглашение, требующее выполнения определенных правил.

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

у него они не обявлены как static, и он пишет, что это все в main файле.

bool line_mode = false;
enum {ORTHOGRAPHIC=0, PERSPECTIVE};
int projection_type=ORTHOGRAPHIC;

static у него наоброт лечит.

а раз при нестатике все собирается без ругани о множественном обьявлении - то дело не в многих экземплярах.

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

alysnix ★★★
()