O que o casting deveria significar?

18

Ao codificar em idiomas de baixo nível como o IC, descobrir que converter às vezes significa 'reinterpretar esses bytes como se sempre tivesse sido desse outro tipo' e, outras vezes, como 'converter esse valor inteligentemente nesse outro tipo'.

Qual é o significado original da palavra e existe alguma consistência em quando esperar uma conversão e quando esperar uma reinterpretação bruta?

Alexander Torstling
fonte
o que há no artigo da Wikipedia que você não entende? " conversão de tipo , conversão de tipo e coerção são maneiras diferentes, implícita ou explicitamente, de alterar uma entidade de um tipo de dados para outro ... Cada linguagem de programação tem suas próprias regras sobre como os tipos podem ser convertidos ..."
gnat
O significado original de "transmitir" não tem nada a ver com programação, veja aqui merriam-webster.com/dictionary/cast
Doc Brown
1
Muitos (principalmente do ponto de vista da linguagem gerenciada) no blog de Eric Lippert na categoria operador de elenco
AakashM
1
@gnat: Não tenho certeza se essa é uma pergunta séria ou apenas uma tentativa de pesca à linha. Mas eu gostaria de saber como saber o que o compilador fará: converter, converter ou coagir? Quais são as regras de ouro?
Alexander Torstling
1
@DocBrown Eu acho que o termo castno sentido da computação é mais semelhante ao vazamento no sentido da metalurgia, pelo qual a forma de um metal fundido é reformada quando derramada em um molde: britannica.com/EBchecked/topic/377665/metallurgy/81884/Casting
precisa saber é o seguinte

Respostas:

10

A transmissão em C é única, diferente de outras línguas. Também nunca é inteligente.

A conversão em C converte valores de um tipo para outro usando regras cuidadosamente definidas. Se você realmente precisa saber, leia o padrão. Caso contrário, os pontos principais são:

  1. A conversão entre tipos inteiros preserva o valor, se possível. Se o destino tiver mais bits, isso será ampliado e geralmente seguro, mas poderá envolver extensão de sinal. Se mais estreito, os bits serão perdidos.
  2. A conversão entre tipos de ponteiro preserva o valor do ponteiro, mas os resultados geralmente são indefinidos, geralmente não portáteis e úteis para cenários avançados.
  3. A conversão entre tipos inteiros e ponteiros será aceitável se o número inteiro for grande o suficiente e preservar o padrão de bits (o que quer que isso aconteça). Se o número inteiro for muito pequeno, o resultado será indefinido, mas não será útil. Como regra, 'long' é largo o suficiente para 'void *', mas não há garantias! Os ponteiros criados dessa maneira podem ser inválidos, de todas as formas interessantes.
  4. Conversão entre tipos float e número inteiro são conversões aritméticas, conforme definido por uma rotina de biblioteca apropriada (com truncamento, não arredondamento).
  5. Você pode converter o valor de retorno de uma função para anular. Eu nunca tenho. Não faz nada.

Algumas conversões são aplicadas implicitamente e, em outras, o compilador emitirá um aviso. Melhor prestar atenção aos avisos!

A definição de dicionário para o elenco é melhor ignorada, pois é inútil. Muitos elencos são melhor descritos pelos termos conversão ou coerção, portanto vale a pena conhecê-los também.

C ++ é MUITO mais complicado, mas você não perguntou isso, perguntou?

david.pfx
fonte
Estou interessado em regras práticas e não em detalhes minúsculos, mas estou interessado em outros idiomas além de C, se isso ajudar a esclarecer as coisas.
Alexander Torstling
2
O que eu dei aqui é tão genérico quanto razoável. Para escrever código C / C ++ profissional real e de baixo nível, os mínimos detalhes são críticos. A maioria dos idiomas simplesmente não tem esse tipo de problema em suas conversões de tipo. Desculpe se isso não resolver o seu problema.
David.pfx
Só que a conversão de T*para void*e volta é sempre bem definido.
Route de milhas
@Miles: Na verdade, é necessário converter T * em qualquer U * e vice-versa para preservar o valor original do ponteiro. Na minha resposta, eu apenas disse 'muitas vezes indefinido' para mantê-lo breve, porque alguns detalhes são muito confusos.
David.pfx
1
@ supercat: Veja n1570 S6.3.2.3. A conversão / deslocamento entre T *, U * e void * sempre preserva o valor do ponteiro com apenas uma exceção. Se qualquer T * não estiver alinhado corretamente, será um comportamento indefinido. Eu aceito o seu ponto, mas apenas nessa medida.
David.pfx
2

Esta parte do dicionário Webster fornece a definição adequada:

a: dar forma a (uma substância) derramando em forma líquida ou plástica em um molde e deixando endurecer sem pressão
b: formar por esse processo

Portanto, antes da transmissão, seu "objeto" (não literalmente um objeto OOP) está em uma determinada forma (tipo). Quando você o molda novamente, isso é "despeje concreto" ao seu redor para torná-lo em uma nova forma, é o que você faz com o vazamento. Você tem um número como um número inteiro em forma de hexágono e, após a conversão, obterá uma sequência em forma de retângulo.

Juha Untinen
fonte
2
Além disso : "Para atribuir uma determinada função a (um ator)".
Kelly Thomas
Sim. Tenho certeza que é o melhor. +1.
David.pfx
2

Pode ser útil separar as conversões C em dois grupos:

  1. Conversões numéricas - converte um número entre uma representação em outra, tentando manter o valor. Por exemplo - (int)3.1seria 3. Existem regras exatas que definem o que acontece quando o valor exato não pode ser mantido.

  2. Transmissões do ponteiro - mantenha o endereço da memória, mas mude a maneira como é desreferenciado. Por exemplo, para float x=3.5, *(int *)&xdará 1080033280- esse número inteiro é representado pelo mesmo padrão de bits que representa o flutuador 3.5.

Ugoren
fonte
Keep the memory address, but change the way it's dereferenced.A desreferenciação de um ponteiro com punção de tipo não está definida. The Standard garante apenas lançando a partir A *de B *e para trás irá produzir o mesmo A *, o que pode não ter sido válido para excluir a referência no 1 º lugar - ou que, se B *é um char *, ele pode ser usado para ler a representação de objeto de qualquer tipo. Para todos os outros tipos, o B *ponteiro de cancelamento de referência é punção de tipo, UB, e viola o aliasing estrito. De qualquer forma, mesmo que o compilador não tenha descartado o exemplo 2 acima por esse motivo, você está fazendo suposições não portáveis ​​sobre padrões de bits
underscore_d
1
cast (v): to receive form in a mold

Em C ++, os vários tipos de conversão podem ser mais explícitos, com o reinterpret_castsignificado de "tratar esses bytes como se eles já fossem essa outra coisa". Em C, você pode tornar isso absolutamente explícito usando a union, a conversão com o (type)operador tentará manter o resultado numericamente equivalente, até a perda de precisão.

U2EF1
fonte
2
No ponteiro C, as projeções são sempre reinterpretadas e as projeções de valor sempre preservam o valor da melhor maneira possível. No C ++, há várias maneiras de fazer a conversão de ponteiro, e é por isso que existem os tipos de conversão mais explícitos.
Jan Hudec 17/01
A semântica de conversão de ponteiro C não é necessariamente "reinterpretada". Seria legítimo que um processador que usasse endereçamento de palavras, mas desejasse interagir bem com o código baseado em bytes, tivesse uma int*que fosse uma palavra e uma char*que fossem duas palavras [com o segundo byte selecionando o byte alto ou baixo de uma palavra]. A conversão de um (int*)para (char*)exigiria a adição de uma palavra extra, que deveria ser qualquer valor que especificasse o primeiro byte do int.
Supercat