Alguém poderia explicar o que
__imp__fprintf
e
__imp____iob_func
meios externos não resolvidos?
Porque recebo estes erros quando tento compilar:
1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: unresolved external symbol __imp__fprintf referenced in function _ShowError
1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: unresolved external symbol __imp____iob_func referenced in function _ShowError
1>E:\Documents\Visual Studio 2015\Projects\SDL2_Test\Debug\SDL2_Test.exe : fatal error LNK1120: 2 unresolved externals
Já posso dizer que o problema não é linkar errado. Vinculei tudo corretamente, mas por algum motivo ele não compila.
Estou tentando usar SDL2.
Estou usando o Visual Studio 2015 como compilador.
Vinculei a SDL2.lib e SDL2main.lib em Linker -> Entrada -> Dependências Adicionais e me certifiquei de que os Diretórios VC ++ estão corretos.
c++
sdl-2
visual-studio-2015
unresolved-external
RockFrenzy
fonte
fonte
Respostas:
Finalmente descobri por que isso está acontecendo!
No visual studio 2015, stdin, stderr, stdout são definidos como segue:
Mas anteriormente, eles eram definidos como:
Portanto, agora __iob_func não está mais definido, o que leva a um erro de link ao usar um arquivo .lib compilado com versões anteriores do visual studio.
Para resolver o problema, você pode tentar definir
__iob_func()
você mesmo que deve retornar um array contendo{*stdin,*stdout,*stderr}
.Em relação aos outros erros de link sobre funções stdio (no meu caso, foi
sprintf()
), você pode adicionar legacy_stdio_definitions.lib às opções do linker.fonte
extern "C"
na declaração / definição.extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
Para Milan Babuškov, IMO, é exatamente assim que a função de substituição deve ser :-)
fonte
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
.A Microsoft tem uma observação especial sobre isso ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):
fonte
#pragma comment(lib, "legacy_stdio_definitions.lib")
- mas isso não corrige o__imp___iob_func
- existe uma biblioteca legada para isso também?Conforme respondido acima, a resposta certa é compilar tudo com o VS2015, mas por interesse o seguinte é minha análise do problema.
Este símbolo não parece ser definido em nenhuma biblioteca estática fornecida pela Microsoft como parte do VS2015, o que é bastante peculiar, pois todos os outros são. Para descobrir por que, precisamos olhar a declaração dessa função e, mais importante, como ela é usada.
Aqui está um snippet dos cabeçalhos do Visual Studio 2008:
Portanto, podemos ver que o trabalho da função é retornar o início de um array de objetos FILE (não manipuladores, o "FILE *" é o identificador, FILE é a estrutura de dados opaca subjacente que armazena os goodies de estado importantes). Os usuários desta função são as três macros stdin, stdout e stderr que são usadas para várias chamadas de estilo fscanf e fprintf.
Agora vamos dar uma olhada em como o Visual Studio 2015 define as mesmas coisas:
Portanto, a abordagem mudou para a função de substituição para agora retornar o identificador de arquivo em vez do endereço da matriz de objetos de arquivo, e as macros mudaram para simplesmente chamar a função passando um número de identificação.
Então, por que eles / nós não podemos fornecer uma API compatível? Existem duas regras principais que a Microsoft não pode violar em termos de sua implementação original via __iob_func:
Qualquer mudança em qualquer uma das opções acima significaria código compilado existente vinculado a ele que iria muito mal se a API fosse chamada.
Vamos dar uma olhada em como FILE foi / é definido.
Primeiro, a definição de FILE do VS2008:
E agora a definição do arquivo VS2015:
Portanto, este é o ponto crucial: a estrutura mudou de forma. O código compilado existente referindo-se a __iob_func se baseia no fato de que os dados retornados são uma matriz que pode ser indexada e que nessa matriz os elementos estão à mesma distância.
As possíveis soluções mencionadas nas respostas acima ao longo dessas linhas não funcionariam (se chamadas) por alguns motivos:
O array FILE _iob seria compilado com VS2015 e, portanto, seria apresentado como um bloco de estruturas contendo um vazio *. Assumindo o alinhamento de 32 bits, esses elementos estariam separados por 4 bytes. Portanto, _iob [0] está no deslocamento 0, _iob [1] está no deslocamento 4 e _iob [2] está no deslocamento 8. Em vez disso, o código de chamada esperará que FILE seja muito mais longo, alinhado a 32 bytes em meu sistema, e assim pegará o endereço do array retornado e adicionará 0 bytes para chegar ao elemento zero (aquele está certo), mas para _iob [1] ele irá deduzir que precisa adicionar 32 bytes e para _iob [2] irá deduzir que ele precisa adicionar 64 bytes (porque é assim que parecia nos cabeçalhos do VS2008). E de fato o código desmontado para VS2008 demonstra isso.
Um problema secundário com a solução acima é que ela copia o conteúdo da estrutura FILE (* stdin), não o identificador FILE *. Portanto, qualquer código do VS2008 estaria olhando para uma estrutura subjacente diferente do VS2015. Isso pode funcionar se a estrutura contiver apenas ponteiros, mas é um grande risco. Em qualquer caso, a primeira questão torna isso irrelevante.
O único hack que consegui imaginar é aquele em que __iob_func percorre a pilha de chamadas para descobrir qual identificador de arquivo real eles estão procurando (com base no deslocamento adicionado ao endereço retornado) e retorna um valor calculado de modo que dá a resposta certa. Isso é tão insano quanto parece, mas o protótipo para x86 apenas (não x64) está listado abaixo para sua diversão. Funcionou bem em meus experimentos, mas sua milhagem pode variar - não é recomendado para uso em produção!
fonte
Eu tive o mesmo problema no VS2015. Eu resolvi isso compilando as fontes SDL2 no VS2015.
fonte
SDL2main
e copiarSDL2main.lib
Não sei porque mas:
Após o inclui, mas antes do seu principal deve corrigi-lo por experiência própria.
fonte
Uma solução mais recente para este problema: use as libs sdl mais recentes em
" https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/?C=M;O=D "
Eles parecem ter corrigido o problema, embora seja apenas a biblioteca de 32 bits (eu acho).
fonte
Ligar significa não funcionar corretamente. Investigando stdio.h de VS2012 e VS2015 o seguinte funcionou para mim. Infelizmente, você tem que decidir se deve funcionar para um de {stdin, stdout, stderr}, nunca mais de um.
fonte
Meu conselho é não (tentar) implementar __iob_func.
Ao corrigir esses erros:
libpngd.v110.lib(pngrutil.obj) : error LNK2001: unresolved external symbol ___iob_func curllib.v110.lib(mprintf.obj) : error LNK2001: unresolved external symbol ___iob_func
Eu tentei as soluções de outras respostas, mas no final, retornar um
FILE*
C-array não corresponde a um array de estruturas IOB internas do Windows. @Volker é certo que ele nunca vai trabalhar para mais de umstdin
,stdout
oustderr
.Se uma biblioteca realmente USAR um desses fluxos, ele irá travar . Contanto que seu programa não faça com que a lib os use, você nunca saberá . Por exemplo,
png_default_error
gravastderr
quando o CRC não corresponde aos metadados do PNG. (Normalmente não é um problema que vale a pena travar)Conclusão: Não é possível misturar as bibliotecas VS2012 (Platform Toolset v110 / v110_xp) e VS2015 +, se usarem stdin, stdout e / ou stderr.
Solução: Recompile suas bibliotecas que têm
__iob_func
símbolos não resolvidos com sua versão atual do VS e um conjunto de ferramentas de plataforma correspondente.fonte
Use o SDL2main.lib e SDL.lib pré-compilados para a biblioteca do seu projeto VS2015: https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/sdl-visualstudio-2225.zip
fonte
Eu resolvo esse problema com a seguinte função. Eu uso o Visual Studio 2019.
como a chamada de função definida pela macro stdin, a expressão "* stdin" não pode ser usada no inicializador de matriz global. Mas o initialier de array local é possível. desculpe, eu sou pobre em inglês.
fonte
Para quem ainda está procurando uma resposta onde os truques acima não funcionaram. A ligação estática é a forma de resolver este problema. Altere as configurações da sua biblioteca Runtime conforme abaixo
Project properties --> C/C++ --> Code generation --> Runtime Library --> Multi-threaded Debug (/MTd) instead of /MDd
fonte
Consegui consertar o problema.
A origem do erro foi esta linha de código, que pode ser encontrada no código-fonte SDLmain.
Então, o que fiz foi editar o código-fonte em SDLmain dessa linha também:
E então eu construí o SDLmain e copiei e substituí o antigo SDLmain.lib em meu diretório de biblioteca SDL2 pelo recém-criado e editado.
Então, quando executei meu programa com SDL2, nenhuma mensagem de erro apareceu e o código foi executado sem problemas.
Não sei se isso vai me morder mais tarde, mas então para tudo está indo muito bem.
fonte
Isso pode acontecer quando você vincula a msvcrt.dll em vez de msvcr10.dll (ou semelhante), o que é um bom plano. Porque isso o deixará livre para redistribuir a biblioteca de tempo de execução do Visual Studio dentro do pacote de software final.
Essa solução alternativa me ajuda (no Visual Studio 2008):
Este snippet não é necessário para o Visual Studio 6 e seu compilador. Portanto, o #ifdef.
fonte
Para trazer mais confusão neste tópico já rico, aconteceu de encontrar o mesmo externo não resolvido em fprintf
Mesmo que no meu caso fosse em um contexto bem diferente: no Visual Studio 2005 (Visual Studio 8.0) e o erro estava acontecendo no meu próprio código (o mesmo que eu estava compilando), não em um terceiro.
Acontece que esse erro foi disparado pela opção / MD em meus sinalizadores de compilador. Mudar para / MT removeu o problema. Isso é estranho porque normalmente, vincular estaticamente (MT) levanta mais problema do que dinamicamente (MD) ... mas caso sirva outro, eu coloco lá.
fonte
No meu caso, este erro vem de minha tentativa de remover dependências da biblioteca de runtime dependente da versão MSVC DLL (msvcr10.dll ou assim) e / ou remover a biblioteca de runtime estática também, para remover o excesso de gordura de meus executáveis.
Portanto, eu uso a opção de vinculador / NODEFAULTLIB, meu "msvcrt-light.lib" feito por mim mesmo (procure no google quando precisar) e
mainCRTStartup()
/WinMainCRTStartup()
entradas.É IMHO desde o Visual Studio 2015, então me concentrei em compiladores mais antigos.
No entanto, definir o símbolo _NO_CRT_STDIO_INLINE remove todo o incômodo e um aplicativo simples "Hello World" tem novamente 3 KB de tamanho pequeno e não depende de DLLs incomuns. Testado no Visual Studio 2017.
fonte
Cole este código em qualquer um dos seus arquivos de origem e recrie. Funcionou para mim!
#include stdio.h
ARQUIVO _iob [3];
ARQUIVO * __cdecl __iob_func (vazio) {
_iob [0] = * stdin;
_iob [0] = * saída padrão;
_iob [0] = * stderr;
return _iob;
}
fonte