Pergunta

Não é preciso dizer que o uso de hard-coded, hex ponteiros literais é um desastre:

int *i = 0xDEADBEEF;
// god knows if that location is available

No entanto, o que é exatamente o perigo em usar literais hexadecimais como variável valores ?

int i = 0xDEADBEEF;
// what can go wrong?

Se estes valores são de fato "perigosa" devido ao seu uso em vários depuração cenários , então isso significa que mesmo se eu não usar esses literais, qualquer programa que durante a execução acontece a tropeçar em cima de um destes valores pode falhar.

Qualquer um cuidado para explicar os perigos reais do uso de literais hexadecimais?


Editar: só para esclarecer, eu não estou me referindo ao uso geral de constantes no código fonte. Estou falando especificamente sobre questões de depuração em cenários que possam surgir com a utilização de valores hexadecimais, com o exemplo específico de 0xDEADBEEF.

Foi útil?

Solução

Eu acredito que a preocupação levantada no endereço IP formatação questão mais cedo hoje não foi relacionada com o uso de literais hexadecimais em geral, mas o uso específico de 0xDEADBEEF. Pelo menos, essa é a maneira que eu lê-lo.

Há uma preocupação com o uso 0xDEADBEEF em particular, mas na minha opinião, é um pequeno. O problema é que muitos depuradores e sistemas de tempo de execução já cooptados este valor particular como um valor marcador para indicar pilha não alocado, maus ponteiros na pilha, etc.

Não me lembro fora do topo da minha cabeça apenas que a depuração e sistemas de tempo de execução usar esse valor particular, mas eu já vi isso usado dessa maneira várias vezes ao longo dos anos. Se você está depurando em um desses ambientes, a existência da constante 0xDEADBEEF em seu código será indistinguível dos valores na RAM não alocado ou o que quer, então o melhor que você não terá como depósitos RAM úteis, e na pior das hipóteses você terá advertências do depurador.

De qualquer forma, isso é o que eu acho que o comentarista originais quis dizer quando disse que era ruim para "utilização em vários cenários de depuração."

Outras dicas

Não há mais perigo em usar um literal hexadecimal do que qualquer outro tipo de literal.

Se a sua depuração sessão termina até a execução de dados como código sem você pretendendo que, você está em um mundo de dor de qualquer maneira.

É claro, há o "valor mágico" normal vs "bem-nomeado constante" questão cheiro de código / limpeza, mas isso não é realmente o tipo de perigo que eu acho que você está falando.

Com poucas exceções, nada é "constante".

Nós preferimos chamá-los de "variáveis ??lentas" - o seu valor muda tão lentamente que não se importa recompilar para mudá-los

.

No entanto, não queremos ter muitos casos de 0x07 tudo através de uma aplicação ou um script de teste, onde cada instância tem um significado diferente.

Queremos colocar uma etiqueta em cada constante que faz com que seja totalmente sem ambiguidades o que significa.

if( x == 7 )

O que "7" significa na declaração acima? É a mesma coisa que

d = y / 7;

É o mesmo significado de "7"?

Casos de Teste são um problema ligeiramente diferente. Nós não precisamos de manejo extensivo, cuidadosa de cada instância de um literal numérico. Em vez disso, precisamos de documentação.

Podemos - até certo ponto -. Explicar onde "7" vem, incluindo um pouco de uma dica no código

assertEquals( 7, someFunction(3,4), "Expected 7, see paragraph 7 of use case 7" );

A "constante" deve ser declarado - e nomeou -. Exatamente uma vez

Um "resultado" em um teste de unidade não é a mesma coisa que uma constante, e requer um pouco de cuidado em explicar de onde veio.

A hex literal não é diferente do que um decimal literal como 1. Qualquer significado especial de um valor é devido ao contexto de um programa específico.

Não há nenhuma razão para que você não deve atribuir 0xdeadbeef a uma variável.

Mas ai do programador que tenta 3735928559 atribuir decimal, ou 33653337357 octal, ou o pior de tudo:. 11011110101011011011111011101111 binário

Big Endian ou Little Endian?

Um perigo é quando constantes são atribuídos a uma matriz ou estrutura com diferentes membros de tamanho; endian -ness do compilador ou máquina (incluindo JVM vs CLR) vai afetar a ordem dos bytes.

Esta questão é verdadeira de valores não constantes, também, é claro.

Aqui está um, na verdade inventado, exemplo. Qual é o valor de buffer [0] após a última linha?

const int TEST[] = { 0x01BADA55,  0xDEADBEEF };
char buffer[BUFSZ];

memcpy( buffer, (void*)TEST, sizeof(TEST));

Eu não vejo nenhum problema em usá-lo como um valor. Seu apenas um número depois de tudo.

Não há perigo em usar um valor hexadecimal codificado para um ponteiro (como seu primeiro exemplo) no contexto certo. Em particular, ao fazer muito desenvolvimento de hardware de baixo nível, esta é a forma de acessar registros mapeados na memória. (Embora, é melhor dar-lhes nomes com um # define, por exemplo). Mas no nível do aplicativo que você não deve precisar fazer um trabalho assim.

Eu uso CAFEBABE Eu não vi isso usado por qualquer depuradores antes.

int *i = 0xDEADBEEF;
// god knows if that location is available

int i = 0xDEADBEEF;
// what can go wrong?

O perigo que vejo é a mesma em ambos os casos: você criou um valor de sinalizador que não tem nenhum contexto imediato. Não há nada sobre i em ambos os casos que me avise 100, 1000 ou 10000 linhas que há um valor potencialmente crítica bandeira associada a ele. O que você plantou é um bug das minas terrestres que, se eu não me lembro de verificar por ele em todos os usos possíveis, eu poderia ser confrontado com um problema de depuração terrível. Cada uso de i agora terá que ficar assim:

if (i != 0xDEADBEEF) { // Curse the original designer to oblivion
    // Actual useful work goes here
}

Repita os passos acima para todos os 7000 casos em que você precisa para usar i em seu código.

Agora, porque é que o acima pior do que isso?

if (isIProperlyInitialized()) { // Which could just be a boolean
    // Actual useful work goes here
}

No mínimo, eu pode detectar várias questões críticas:

  1. Spelling : eu sou um digitador terrível. Como facilmente você vai manchar 0xDAEDBEEF em uma revisão de código? Ou 0xDEADBEFF? Por outro lado, eu sei que a minha compilação vai vomitar imediatamente em isIProperlyInitialised () (inserir o obrigatório s vs. z debate aqui).
  2. Exposição de sentido . Ao invés de tentar esconder suas bandeiras no código, você criou intencionalmente um método que o resto do código pode ver.
  3. Oportunidades para acoplamento . É inteiramente possível que um ponteiro ou referência está ligado a um cache vagamente definida. Uma verificação de inicialização pode ser sobrecarregado para verificar primeiro se o valor está em cache, em seguida, para tentar trazer de volta em cache e, se tudo isso falhar, retorno falsa.

Em suma, é tão fácil de escrever o código que você realmente precisa, pois é para criar um valor magia misteriosa. O código-mantenedor do futuro (que muito provavelmente vai ser você) vai agradecer.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top