Pergunta

Em vez de enviar um ponteiro real para um valor, o valor é fundido para um ponteiro. Encontrei esses exemplos no código da interface da GUI de um programa GTK.

g_signal_connect (pastebutton[pane],
                  "clicked",
                  G_CALLBACK(on_paste_button_pressed),
                  (void*)((long)pane<<4));

No exemplo acima, estou me referindo ao último parâmetro de g_signal_connect. Quando on_paste_button_pressed é chamado por GTK2, on_paste_button_pressed lança o user_data Void Pointer de volta assim:

int pane = ((long)user_data) >> 4;

Na verdade, adicionei esse exemplo específico ao código, mas baseei -o no que já estava lá. Adicionei a mudança de bits para evitar avisos sobre o elenco. O programa em si possui quatro painéis contendo vários widgets, os botões de cópia e pasta permitem copiar todos os valores de um painel para outro.

É essa maneira de lançar um valor para um endereço de ponteiro frequentemente usado e existem razões pelas quais isso não deve ser usado?

editar:

O elenco de um número inteiro para um ponteiro vazio também pode ser alcançado assim:

void* void_ptr = some_int - NULL;
Foi útil?

Solução

Isso é usado. Isso é usado bastante comumente quando faz o que é necessário.

Uma razão para não usá -lo é que o tamanho teoricamente do ponteiro pode ser menor que o tamanho inteiro da fonte.

Outro motivo para não usá -lo é que ele permite que você passe apenas uma parte dos dados inteiros para o retorno de chamada. Se no futuro você precisar adicionar outra parte dos dados (ou mudar para um não inteiro), precisará localizar e reescrever todos os lugares onde o retorno de chamada fizer acesso aos dados passados. Então, se houver uma chance de que você tenha que estender os dados no futuro, é melhor criar um struct (mesmo que seja apenas um único int neste momento) e passar um ponteiro para isso struct.

Mas se você tem certeza de que nunca terá que passar outra coisa senão esse número inteiro único e que seu número inteiro se encaixa em um void *, então essa técnica não está de forma alguma quebrada.

Ps Pedanticamente falando, nem C nem C ++ parecem ter a garantia de ida e volta para conversão inteira-a-void *-para-integer, ou seja, eles não garantem que ele funcione e restaurará o valor integral original.

Outras dicas

Você deve usar o macros gint_to_pointer () e gpointer_to_int () para lançar entre ponteiros e números inteiros.

Glib: Macros de conversão do tipo

Ficar um número inteiro para um ponteiro é usado para passar um valor por valor. Esta é a maneira preferida se você precisar de um parâmetro de referência, porque o compilador não precisa desreferenciar o ponteiro.

A mudança de bit é uma má ideia, porque pode causar transbordamentos.

Para um código realmente portátil, você deve usar intptr_t como seu tipo de número inteiro porque ele se encaixará muito bem em um ponteiro.

Ele vê o uso nesses tipos de casos, sim. Funciona em muitas plataformas, mas pode falhar porque um número inteiro arbitrário nem sempre é um valor de ponteiro válido, embora a mudança que você faça deve contornar isso. Também é possível que um ponteiro não possa conter todos os valores que um número inteiro pode; Este seria o caso se você estiver usando um 64 bits long Em uma plataforma em que os ponteiros têm 32 bits e, é claro, como você está mudando o valor, também pode falhar, mesmo que ponteiros e números inteiros tenham o mesmo tamanho. Se você quiser usar esse truque, provavelmente deve verificar sizeof (void*) Contra o tamanho do tipo inteiro que você usa e, no tempo de execução, a verificação em relação ao valor real se o ponteiro não for grande o suficiente. Provavelmente não vale a pena fazer isso totalmente portátil, para que você use um ponteiro real em plataformas onde isso é necessário; portanto, limite -se às plataformas em que esse truque funciona ou abandone o truque completamente.

Eu acho isso bem. Não tem estatísticas sobre frequência de uso, mas você realmente se importa?

Não tenho certeza se entendi como a mudança de bit ajuda.

É usado, mas não é portátil, então você deve ter cuidado.

O padrão C não exige que os tipos de ponteiros tenham pelo menos tantos bits quanto os tipos inteiros; portanto, você nem sempre pode fazê -lo.

Mas não me lembro algum plataforma em que os ponteiros têm na realidade foi menor que os números inteiros, então você provavelmente está seguro (apesar de não ser tecnicamente seguro).

A única razão pela qual posso pensar que o elenco pode estar lá é remover a possibilidade de avisos de alinhamento. Seção 6.3.2.3 do C1X Draft States:

Um número inteiro pode ser convertido em qualquer tipo de ponteiro. Exceto como especificado anteriormente, o resultado é definido pela implementação, pode não estar alinhado corretamente, pode não apontar para uma entidade do tipo referenciado e pode ser uma representação de armadilha.

Isto é do C-FAQ:

Q: Como os números inteiros são convertidos de e para os ponteiros? Posso colocar temporariamente um número inteiro em um ponteiro ou vice -versa?

R: Era uma vez, era garantido que um ponteiro pudesse ser convertido em um número inteiro (embora nunca se soubesse se um INT ou um longo poderia ser necessário) e que um número inteiro poderia ser convertido em um ponteiro e que um ponteiro permaneceu inalterado quando convertido em um número inteiro (grande o suficiente) e de volta, e que as conversões (e qualquer mapeamento) pretendiam ser `` sem surpresa para aqueles que conhecem a estrutura de endereçamento da máquina '', em outras palavras, existe Alguns precedentes e suporte para conversões inteiros/ponteiros, mas sempre foram dependentes da máquina e, portanto, não portáveis. Os elencos explícitos sempre foram necessários (embora os primeiros compiladores raramente se queixassem se você os deixasse de fora).

O padrão ANSI/ISO C, a fim de garantir que C seja amplamente implementável, enfraqueceu essas garantias anteriores. As conversões de ponteiro-inteiro e número inteiro-ponteiro são definidas por implementação (ver Pergunta 11.33) e não há mais garantia de que os ponteiros possam ser convertidos para números inteiros e voltas, sem alterações.

Forçar ponteiros a inteiros, ou números inteiros em ponteiros, nunca foi uma boa prática. Quando você precisa de um slot genérico que possa conter um tipo de dados, um sindicato é uma ideia muito melhor.

Veja também as perguntas 4.15, 5.18 e 19.25.

Referências: K & R1 Sec. A14.4 p. 210 K & R2 Sec. A6.6 p. 199 ISO Sec. 6.3.4 Racional Sec. 3.3.4 Sec. 6.2.3 p. 170, Sec. 6.2.7 pp. 171-2

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