G++ ошибка? (bool_val? 0: 1) не возвращает ни 0, ни 1

Я воспроизведу проблему этой простой демонстрацией:

// bool_test_func.cpp
#include <stdio.h>

void func(bool* b) {
  int a = (*b ? 0 : 1);
  printf("%d\n", a); // EXPECT ether 0 or 1 here
}

// bool_test.cpp
void func(bool* b);

int main() {
  int n = 128;
  func((bool*)&n);
  return 0;
}

-O0 скомпилировать и запустить:

g++ -g -O0 -Wall -o bool_test bool_test.cpp bool_test_func.cpp
[email protected]:~/testing/c++$ ./bool_test
0

-O1 скомпилировать и запустить (неожиданный результат):

g++ -g -O1 -Wall -o bool_test bool_test.cpp bool_test_func.cpp
[email protected]:~/testing/c++$ ./bool_test
129

Когда я проверяю код -O2 ASM, я думаю, что это ошибка g++, g++-код оптимизации всегда считает значение bool равно 1 или 0:

    00000000004005e6 :
      4005e6:       48 83 ec 08             sub    $0x8,%rsp
      4005ea:       0f b6 37                movzbl (%rdi),%esi
      4005ed:       83 f6 01                xor    $0x1,%esi  #just XOR the bool val
      4005f0:       40 0f b6 f6             movzbl %sil,%esi
      4005f4:       bf 94 06 40 00          mov    $0x400694,%edi
      4005f9:       b8 00 00 00 00          mov    $0x0,%eax
      4005fe:       e8 9d fe ff ff          callq  4004a0 
      400603:       48 83 c4 08             add    $0x8,%rsp
      400607:       c3                      retq
      400608:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
      40060f:       00

 

gcc версия 4.9.2 (Debian 4.9.2-10)

Это поведение g++ по дизайну? Как я могу отключить эту неправильную оптимизацию? Благодаря ~

Ответы

Ответ 1

Я думаю, что это ошибка g++.

Приходится с уважением не соглашаться.

Как отключить эту неправильную оптимизацию?

Даже если это возможно, это на самом деле не так: -)

Вы передаете указатель non-bool в качестве указателя bool (базовый элемент не относится к типу bool), и я уверен, что это (известное как punning) вызывает undefined поведение.

Следовательно, код может делать все, что захочет.

Вы можете подумать о прототипе void func(bool* b) как о контракте, в котором вы согласны, чтобы когда-либо передавать указатели на значения bool. Если вы нарушите этот контракт, все ставки будут отключены. В этом конкретном случае ваш код:

int a = (*b ? 0 : 1);

говорит ему преобразовать false в 1 и true в 0. Если вы должны были ввести действительный ввод (false/0 или true/1), то xor input, 1 будет именно то, что нужно сделать.

Однако, поскольку вы даете 128, xor приводит к 129.