Беззнаковые целые в MinGW-w64

Тема в разделе "LANGS.C", создана пользователем _qwe8013, 18 окт 2017.

  1. _qwe8013

    _qwe8013 Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    90
    В общем пишу на сишечке программу, компилирую MinGW-w64. Захотелось мне тут посмотреть на свой код через IDA Pro. Для примера взял такой код:
    Код (C):
    1. for(unsigned int i=0; i<MSize*MSize; i++)
    MSize объявлен как unsigned int. Вижу в качестве проверки условия в IDA Pro:
    Код (ASM):
    1. loc_40167A:
    2. mov     eax, [rbp-40h+MSize]
    3. imul    eax, [rbp-40h+MSize]
    4. cmp     [rbp-40h+i], eax
    5. jb      short loc_401644
    Т.о. при проверке условия он делает знаковое умножение, это вообще нормально? И как с этим бороться? Я понимаю, что вряд ли квадрат переменной MSize выйдет за пределы максимального знакового целого, но всё-таки такое поведение компилятора раздражает.
     
  2. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    1.532
    вполне нормально, если отключена оптимизация, или MSize - глобальная переменная, то есть может быть в любое время изменена из другого потока...
     
  3. _qwe8013

    _qwe8013 Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    90
    А почему если MSize - глобальная переменная, то он такую фигню делает? Собрал программу в Release конфигурации (опции компилятора: "-O2;-Wall"), но всё равно он юзает imul.
     
  4. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    1.532
    я же писал: MSize может быть изменена из другого потока, если это глобальная переменная, тогда выражение MSize * MSize нужно вычислять на каждой иттерации цикла, чтобы не терять семантику написанного кода... чтобы этого не было, объяви переменную auto MSize2 = MSize * MSize, и используй ее в качестве предела для иттераций цикла...

    есть еще -O3... -Wall не имеет никакого отношения к оптимизации...
     
  5. _qwe8013

    _qwe8013 Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    90
    Rel, кажется вы меня не правильно поняли. Проблема не в том, что произведение вычисляется на каждой итерации, а в том, что вместо беззнакового умножения mul используется знаковое imul.
     
  6. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    1.532
    а, сорян... насчет этого не знаю... можно канеш предположить, что imul выполняется быстрее mul... но это странно... думаю, что тебе лучше об этом спросить в мейл-листе GCC или MinGW...
     
  7. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    1.744
    Проблемы нет, так как отличие знакового умножения от беззнакового только в устанавливаемых флагах; в edx:eax будет одно и то же.
     
  8. _qwe8013

    _qwe8013 Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    90
    При форме imul такой, как я привёл в #1 в edx ничего записано не будет. А на счёт того, что разницы не будет, это - да, я не подумал (разница будет в верхнем двойном слове, которое никуда записано не будет).
     
  9. SadKo

    SadKo Владимир Садовников

    Публикаций:
    1
    Регистрация:
    4 июн 2007
    Сообщения:
    1.123
    Адрес:
    г. Санкт-Петербург
    Вообще, использовать голый unsigned int нынче некошерно. Лучше что-нить типа size_t. Ну и умножение лучше из for вынести в отдельную переменную. Не всяк компилятор умён настолько.
    По поводу imul - всё уже правильно сказали.
     
  10. _qwe8013

    _qwe8013 Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    90
    SadKo, А что собственно плохого в использовании unsigned int?
     
  11. SadKo

    SadKo Владимир Садовников

    Публикаций:
    1
    Регистрация:
    4 июн 2007
    Сообщения:
    1.123
    Адрес:
    г. Санкт-Петербург
    Да, в принципе, не много плохого: писать приходится немного больше символов, чем size_t, и портабельность страдает: на x32 sizeof(unsigned int) = 32, sizeof(size_t) = 32, а вот на x64 sizeof(unsigned int) = 32, а sizeof(size_t) = 64.
     
  12. _qwe8013

    _qwe8013 Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    90
    Чего-то не вижу, чтобы портабельность страдала.
     
  13. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    48
    В C++ чтение произвольной переменной, которая потенциально меняется в другом потоке, без должной синхронизации (установления отношения happens before) называется data race и приводит к неопределённому поведению.
    Короче, не может глобальная переменная (не atomic) в любое время меняться из другого потока.

    Не нужно и никто не вычисляет, в чём можно легко убедиться.
    Берём код
    Код (C):
    1.  
    2. unsigned MSize = 30;
    3. unsigned f()
    4. {
    5.    unsigned ret = 0;
    6.    for (unsigned i = 0; i < MSize*MSize; i++)
    7.      ret += i;
    8.    return ret;
    9. }
    10.  
    и компилируем gcc:
    Код (ASM):
    1.  
    2. f():
    3. mov ecx, DWORD PTR MSize[rip]
    4. imul ecx, ecx
    5. test ecx, ecx
    6. je .L4
    7. xor edx, edx
    8. xor eax, eax
    9. .L3:
    10. add eax, edx
    11. add edx, 1
    12. cmp edx, ecx
    13. jne .L3
    14. rep ret
    15. .L4:
    16. xor eax, eax
    17. ret
    18. MSize:
    19. .long 30
    20.  
    или msvc:
    Код (ASM):
    1.  
    2. MSize DD 01eH
    3. f PROC
    4. mov r9d, DWORD PTR MSize
    5. xor ecx, ecx
    6. imul r9d, r9d
    7. mov edx, ecx
    8. mov r10d, ecx
    9. mov eax, ecx
    10. cmp r9d, 2
    11. jb SHORT $LC10@f
    12. lea r8d, DWORD PTR [r9-1]
    13. npad 2
    14. $LL11@f:
    15. inc edx
    16. add ecx, eax
    17. add edx, eax
    18. add eax, 2
    19. cmp eax, r8d
    20. jb SHORT $LL11@f
    21. $LC10@f:
    22. cmp eax, r9d
    23. cmovb r10d, eax
    24. lea eax, DWORD PTR [rdx+rcx]
    25. add eax, r10d
    26. ret 0
    27. f ENDP
    28.  

    Ну а насчёт imul уже сказали. Но я тоже скажу.
     
  14. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    6
    Регистрация:
    25 июн 2008
    Сообщения:
    2.491
    Код (C++):
    1. unsigned MSize = 30;
    2. unsigned f()
    3. {
    4.    unsigned ret = 0;
    5.    for (unsigned i = 0; i < MSize*MSize; i++)
    6.      ret += i;
    7.    return ret;
    8. }
    а нужно вычислять?
    Код (C++):
    1. unsigned ret = 900;
     
  15. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    48
    Mikl___, смелая замена. Но некорректная.
     
  16. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    6
    Регистрация:
    25 июн 2008
    Сообщения:
    2.491
    CurryHowardIsomorphism,
    Excusez-moi, je me suis dépêché et mal interprété la condition
    Код (C++):
    1. ret = 405000 // (1+899)*450
     
  17. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    48
    Mikl___, да я даже не про арифметику (кстати, она опять некорректная, должно быть 404550), а что замена здесь на константу неправомерна.