Блог пользователя Ixanezis

Автор Ixanezis, 13 лет назад, По-русски

Это - http://pastebin.com/YX2BB9yF - кусок неверной программы для таски с прошлого CF, но речь не об этом. А речь о том, что VSE 2010 в debug и release модах выдаёт соответственно 4 и 2. Кэп подсказывает, что где-то там память повредилась, что-то куда вылезло и т.п. Впрочем, где я с памятью плохо работаю, я так и не нашёл и уже даже думаю, что не в этом дело.

Вот некоторые особенности этой программы:

1) раскомменчивание строк 43-45 выдаёт 4 стабильно во всех случаях.

2) В GNU при компиляции без параметров и с параметрами -O3 выдаёт всегда 4.

3) Есть подозрение, что это всё строчки 67 - 70: они повергают компилятор в шок и из-за этого он что-то неверно оптимизирует.

В общем, если кто знает-таки в чём дело, тому печенька...

  • Проголосовать: нравится
  • -1
  • Проголосовать: не нравится

13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

По ссылке открывается страница без кода. (Прошло)
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Единственное что могу предположить - что-то не заполнилось нулями. 67-70 не похоже на что-то сильно страшное, правда оно может свернуться в ++len, но в данном случае в этом нет ничего плохого. с учетом того что в дебаг-моде все нормально, скорее всего все-таки что-то с нулями.
Обычно такие вещи ищутся бин.поиском по коду.  Коментим половину - и либо удаляем вторую, либо сильно упрощаем первую. В результате получится маленький код на котором будет очевидна бага компилятора, либо ваша.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

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

    А если то, что должно свернуться в ++len, явно заменить на ++len, то ответ вообще 1. Явно что-то мутное.

    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      В дебаг и в релиз моде инициализация может работать по разному. Рекомендую все таки минимизировать код. по такому большому ничего не понятно.
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Ну я и так уже постарался его привести к более-менее компактному виду. Проблема в том, что удаление почти любого куска кода уже приводит к нормальному результату. (Впрочем, как и добавление какой-нибудь строчки вида if (false) cout << "hello" << endl;)

        В общем ладно, не так это важно. Спасибо за помощь.

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Выпиливание из функции DFS1 по сути не используемых переменных reg1 и reg2, и замена строк 67-70 на ++len; привели к результату 4-4. Забавно что добавление любого вывода в любое место этой функции приводит к тому же результату. Без понятия почему это происходит=)
13 лет назад, # |
  Проголосовать: нравится +4 Проголосовать: не нравится
исключением ненужностей сократил DFS1 до такого вида (неважно, что смысл функции потерян, главное что расхождение дебаг и релиз версий сохраняется):

int DFS1(int x)
{
    ++len;
    for (int i=0; i<26; i++)
        if (reg[i] == from[x].reg2)
            return -1;

    int reg2 = DFS1(from[x].reg2);
    return -1;
}

В дебаге возвращает 3, в релизе 2. По листингам дизассемблера видно, что инициализация reg2 выброшена (что логично) вместе с рекурсивным вызовом (что нелогично). 

int DFS1(int x)
{
    ++len;
012F1040  inc         dword ptr [len (12F4FECh)]  
012F1046  lea         eax,[eax+eax*2]  
012F1049  mov         ecx,dword ptr from+4 (12F43CCh)[eax*4]  
012F1050  mov         eax,offset reg (12F4FF0h)  
        if (reg[i] == from[x].reg2)
012F1055  cmp         dword ptr [eax],ecx  
012F1057  je          DFS1+23h (12F1063h)  
    for (int i=0; i<26; i++)
012F1059  add         eax,4  
012F105C  cmp         eax,offset reg+68h (12F5058h)  
012F1061  jl          DFS1+15h (12F1055h)  
            return -1;

    int reg2 = DFS1(from[x].reg2);
    return -1;
012F1063  or          eax,0FFFFFFFFh  
}
012F1066  ret



Если закомментировать /*int reg2 =*/, компилер понимает, что рекурсия тут была неспроста, тогда работает правильно, то есть одинаково в обоих режимах.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Наверное, самым простым фиксом будет объявить len со спецификатором volatile. Тогда компилер не умничает и понимает, что переменная ещё где-то нужна кроме текущей процедуры. Но то, что он сам до этого не додумывается, конечно, печально.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А такой код

    int count = 0;
    
    int test(int x)
    {
        ++count;
        if(x == 10)
            return -1;
        int foo = test(x + 1);
        return -1;
    }
    
    void main()
    {
        test(0);
        printf("%d\n", count);
    }

    в релизе превратился в нечто подобное такому

    int __fastcall test()
    {
        ++count;
        return -1;
    }
    
    int __fastcall main()
    {
        count += 2;
        test();
        printf("%d\n", count);
        return 0;
    }

    В общем прикольные грабли

  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Кстати,
    012F1046  lea         eax,[eax+eax*2]