Em C++, fazer funções de aridade variável (aqueles com ... no final da lista de parâmetros) seguem necessariamente o __cdecl convenção de chamada?

StackOverflow https://stackoverflow.com/questions/2512746

Pergunta

Eu sei que __stdcall funções não pode ter reticências, mas quero ter certeza que não existem plataformas que suportam o stdarg.h funções de convenções de chamada diferente __cdecl ou __stdcall.

Foi útil?

Solução

A convenção de chamada tem que ser aquele onde o chamador afasta os argumentos da pilha (porque o receptor não sei o que vai ser transmitido).

Que não corresponde, necessariamente, para o que a Microsoft chama de "__cdecl" embora.Apenas para exemplo, em um SPARC, ele irá passar normalmente os argumentos em registros, porque é como o SPARC é projetado para funcionar -- os seus registos, basicamente, agir como uma pilha de chamada que é derramado para a memória principal se chama obter profundo o suficiente para que eles não se encaixam em registrar mais.

Que eu sou menos certos sobre isso, eu esperaria aproximadamente o mesmo em IA64 (Itanium) -- ele também tem um grande conjunto de registradores (duzentas se a memória serve).Se eu não estou enganado, é um pouco mais permissivas sobre como utilizar os registradores, mas eu esperava que ele seja usado da mesma forma em menos de um monte de tempo.

Por que isso importa para você?O ponto de usar stdarg.h e suas macros é para esconder as diferenças na convenção de chamada do seu código, para que ele possa trabalhar com a variável de argumentos portável.

Editar, com base nos comentários:Ok, agora eu entendo o que você está fazendo (pelo menos o suficiente para melhorar a resposta).Considerando que você já está (aparentemente) tem o código para lidar com as variações no padrão ABI, as coisas são mais simples.Que só deixa a questão de saber se a aridade variável funções de sempre usar o padrão "ABI", o que quer que seja para a plataforma ao lado.Com "stdcall" e "padrão" como as únicas opções, eu acho que a resposta é sim.Apenas para exemplo, no Windows, wsprintf e wprintf quebrar a regra de ouro, e usa cdecl convenção de chamada em vez de stdcall.

Outras dicas

Mais definitiva maneira que você pode determinar isso é analisar as convenções de chamada.Para funções de aridade variável, a convenção de chamada precisa de um par de atributos:

  • O receptor deve ser capaz de acessar os parâmetros que não fazem parte da lista de argumento variável a partir de um fixo deslocamento do topo da pilha.Isso requer que o compilador empurrar os parâmetros para a pilha da direita para a esquerda.(Isto inclui coisas como o primeiro parâmetro para printf, a especificação de formato.Além disso, o endereço da variável de lista de argumento em si também deve ser derivada a partir de um local conhecido.)
  • O chamador deve ser responsável por remover os parâmetros na pilha uma vez que a função retornou, porque só o compilador ao gerar o código para o chamador, sabe quantos parâmetros foram enviados para a pilha em primeiro lugar.A aridade variável função em si não tem esta informação.

stdcall não trabalho porque o receptor é responsável por popping parâmetros na pilha.Na idade de 16 bits do Windows dias, pascal não funciona, porque é empurrado parâmetros na pilha da esquerda para a direita.

É claro que, como as outras respostas que se aludiu, muitas plataformas de não lhe dar qualquer escolha em termos da convenção de chamada, fazendo com que esta questão irrelevante para aqueles.

Considere a seguinte função em um sistema X86:

void __stdcall alguma coisa (char *, ...);

A função declara-se como __STDCall, que é uma convenção de callee-limpe. Mas uma função variadica não pode ser limpa de callee, pois o callee não sabe quantos parâmetros foram passados, por isso não sabe quantos deve limpar.

O compilador Microsoft Visual Studio C/C ++ resolve esse conflito convertendo silenciosamente a convenção de chamada em __cdecl, que é a única convenção de chamada variada suportada para funções que não ocorrem um parâmetro oculto.

Por que essa conversão ocorre silenciosamente em vez de gerar um aviso ou erro?

Meu palpite é que é para tornar o compilador Opções /GR (defina a convenção de chamada padrão como __fastCall) e /gz (defina a Convenção de Chamada Padrão como __stdcall) menos irritante.

A conversão automática de funções variádicas em __cdecl significa que você pode simplesmente adicionar a troca de linha de comando /gr ou /gz às opções do compilador, e tudo ainda será compilado e executado (apenas com a nova convenção de chamada).

Outra maneira de olhar para isso não é pensar no compilador como Convertendo __stdCall variadic em __cdecl, mas simplesmente dizendo "para funções variáticas, __stdcall é um limite de chamadas".

Clique aqui

Você quer dizer 'plataformas suportadas pelo msvc "ou como regra geral? Mesmo se você se limitar às plataformas suportadas pelo MSVC, você ainda tem situações como IA64 e AMD64 onde há apenas a convenção de "um", e essa convenção de chamadas é chamada __stdcall, mas certamente não é o mesmo __stdcall Você entra em x86.

Afaik, a diversidade de convenções de chamadas é exclusiva do DOS/Windows no x86. A maioria das outras plataformas possuía compiladores com o sistema operacional e padroniza a convenção.

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