Enums Retornando Valores Errados com /MT vs /MD

Jeison C. | Feb 10, 2026 min read

Encontrei um bug interessante hoje ao compilar um projeto C++. Um enum que deveria retornar o valor 2 estava retornando 0.

enum ENUM {A, B, C};
ENUM c = ENUM::C;
int x = static_cast<int>(c);
// Esperado: x = 2
// Resultado: x = 0

A variável c foi explicitamente inicializada com ENUM::C, mas o cast para int retornava 0 (valor de A) ao invés de 2.

A Solução Temporária

Modificando a declaração para especificar o tipo subjacente, o problema desapareceu:

enum ENUM : int {A, B, C};
ENUM c = ENUM::C;
int x = static_cast<int>(c);
// Agora: x = 2 (correto)

Mas por que isso fez diferença?

A Causa Real

O verdadeiro culpado era a mistura de flags de compilação. Eu estava linkando parte do projeto com /MT (runtime estática) enquanto o restante usava /MD (runtime dinâmica).

Quando você mistura /MT e /MD em diferentes partes do mesmo projeto, acaba com múltiplas cópias da runtime do C++. Cada runtime pode ter decisões diferentes sobre layout de memória, alinhamento e escolha de tipos subjacentes para enums.

O cenário típico:

Módulo A (compilado com /MD):
  - Define e inicializa o enum
  - Escolhe unsigned char como tipo subjacente
  - Escreve C = 2 na memória

Módulo B (compilado com /MT):
  - Lê o mesmo enum
  - Assume int como tipo subjacente
  - Interpreta os bytes de forma diferente
  - Resultado: lê como A = 0

Por Que Especificar o Tipo Funciona

Ao declarar explicitamente o tipo subjacente do enum:

enum ENUM : int {A, B, C};

Você força ambas as runtimes a usarem a mesma representação binária, eliminando a ambiguidade. Sem especificar o tipo, o compilador escolhe automaticamente (pode ser int, unsigned int, char, etc.), e diferentes módulos podem fazer escolhas diferentes.

A Solução Correta

Especificar o tipo do enum resolve o sintoma, mas não a causa. A solução correta é nunca misturar /MT e /MD no mesmo projeto.

No Visual Studio, configure a runtime library:

  1. Propriedades do projeto
  2. C/C++ → Geração de Código → Biblioteca de Runtime
  3. Release: Multi-threaded DLL (/MD)
  4. Debug: Multi-threaded Debug DLL (/MDd)
  5. Aplique para todos os projetos da solução

Depois, faça um rebuild completo:

Limpar Solução → Recompilar Tudo

Outros Problemas da Mistura de Runtimes

O bug de enum é apenas um sintoma. Misturar /MT e /MD pode causar problemas mais graves:

  • Corrupção de heap ao alocar memória em uma runtime e liberar em outra
  • Crashes aleatórios difíceis de debugar
  • Memory leaks silenciosos
  • Comportamento indefinido com variáveis estáticas e singletons
  • Violações de acesso aparentemente aleatórias

Boas Práticas

Mesmo após corrigir o problema de runtime, é recomendado especificar o tipo subjacente dos enums:

// Recomendado
enum Status : int { OK, Error, Warning };
enum class Color : uint8_t { Red, Green, Blue };

// Evite
enum Status { OK, Error, Warning };

Especificar o tipo garante tamanho previsível, melhor compatibilidade binária e previne bugs sutis de layout.

C++17 e Direct-List-Initialization

C++17 introduziu uma melhoria para inicialização de enums:

enum class Color : uint32_t { Red, Green, Blue };

// C++17: permite inicialização direta com chaves
Color c{2};

// Ainda requer cast explícito para conversões implícitas
Color c = 2;  // Erro
int x = Color::Red;  // Erro

Conclusão

Um valor de enum aparentemente simples retornando incorretamente revelou um problema de configuração de build. Bugs desse tipo podem passar despercebidos em testes e aparecer apenas em produção, causando problemas intermitentes difíceis de rastrear.

A lição: sempre verifique as configurações de compilação e mantenha consistência nas flags de runtime em todo o projeto.