Quelqu'un pourrait-il expliquer ce que
__imp__fprintf
et
__imp____iob_func
des moyens externes non résolus?
Parce que j'obtiens ces erreurs lorsque j'essaye de compiler:
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
Je peux déjà dire que le problème n'est pas lié à une mauvaise liaison. J'ai tout lié correctement, mais pour une raison quelconque, il ne se compilera pas.
J'essaye d'utiliser SDL2.
J'utilise Visual Studio 2015 comme compilateur.
J'ai lié à SDL2.lib et SDL2main.lib dans Linker -> Input -> Additional Dependencies et je me suis assuré que les répertoires VC ++ sont corrects.
c++
sdl-2
visual-studio-2015
unresolved-external
RockFrenzy
la source
la source
Réponses:
J'ai enfin compris pourquoi cela se produit!
Dans Visual Studio 2015, stdin, stderr, stdout sont définis comme suit:
Mais auparavant, ils étaient définis comme:
Alors maintenant, __iob_func n'est plus défini, ce qui entraîne une erreur de lien lors de l'utilisation d'un fichier .lib compilé avec les versions précédentes de visual studio.
Pour résoudre le problème, vous pouvez essayer de définir
__iob_func()
vous-même ce qui devrait renvoyer un tableau contenant{*stdin,*stdout,*stderr}
.En ce qui concerne les autres erreurs de lien sur les fonctions stdio (dans mon cas, c'était le cas
sprintf()
), vous pouvez ajouter legacy_stdio_definitions.lib à vos options de l'éditeur de liens.la source
extern "C"
dans la déclaration / définition.extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
Pour Milan Babuškov, IMO, voici exactement à quoi devrait ressembler la fonction de remplacement :-)
la source
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
.Microsoft a une note spéciale à ce sujet ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):
la source
#pragma comment(lib, "legacy_stdio_definitions.lib")
- mais cela ne résout pas le problème__imp___iob_func
- existe-t-il également une bibliothèque héritée pour cela?Comme indiqué ci-dessus, la bonne réponse est de tout compiler avec VS2015, mais pour l'intérêt, voici mon analyse du problème.
Ce symbole ne semble pas être défini dans une bibliothèque statique fournie par Microsoft dans le cadre de VS2015, ce qui est assez particulier puisque tous les autres le sont. Pour découvrir pourquoi, nous devons examiner la déclaration de cette fonction et, plus important encore, comment elle est utilisée.
Voici un extrait des en-têtes de Visual Studio 2008:
Nous pouvons donc voir que le travail de la fonction est de renvoyer le début d'un tableau d'objets FILE (pas de handles, le "FILE *" est le handle, FILE est la structure de données opaque sous-jacente stockant les goodies d'état importants). Les utilisateurs de cette fonction sont les trois macros stdin, stdout et stderr qui sont utilisées pour divers appels de style fscanf, fprintf.
Voyons maintenant comment Visual Studio 2015 définit les mêmes choses:
L'approche a donc changé pour que la fonction de remplacement renvoie maintenant le descripteur de fichier plutôt que l'adresse du tableau d'objets de fichier, et les macros ont changé pour appeler simplement la fonction en passant un numéro d'identification.
Alors pourquoi ne peuvent-ils / nous fournir une API compatible? Il existe deux règles clés que Microsoft ne peut pas enfreindre en ce qui concerne leur implémentation d'origine via __iob_func:
Tout changement dans l'un ou l'autre des éléments ci-dessus signifierait que le code compilé existant lié à celui-ci irait très mal si cette API est appelée.
Voyons comment FILE a été / est défini.
Tout d'abord la définition du fichier VS2008:
Et maintenant la définition du fichier VS2015:
Il y a donc le nœud du problème: la structure a changé de forme. Le code compilé existant faisant référence à __iob_func repose sur le fait que les données renvoyées sont à la fois un tableau qui peut être indexé et que dans ce tableau les éléments sont à la même distance l'un de l'autre.
Les solutions possibles mentionnées dans les réponses ci-dessus dans ce sens ne fonctionneraient pas (si elles étaient appelées) pour plusieurs raisons:
Le tableau FILE _iob serait compilé avec VS2015 et serait donc présenté comme un bloc de structures contenant un void *. En supposant un alignement de 32 bits, ces éléments seraient séparés de 4 octets. Donc _iob [0] est à l'offset 0, _iob [1] est à l'offset 4 et _iob [2] est à l'offset 8. Le code appelant s'attendra à la place à ce que FILE soit beaucoup plus long, aligné à 32 octets sur mon système, et ainsi il prendra l'adresse du tableau retourné et ajoutera 0 octet pour arriver à l'élément zéro (celui-là est correct), mais pour _iob [1] il en déduira qu'il a besoin d'ajouter 32 octets et pour _iob [2] il en déduira qu'il a besoin d'ajouter 64 octets (car c'est à quoi cela ressemblait dans les en-têtes VS2008). Et en effet, le code désassemblé pour VS2008 le démontre.
Un problème secondaire avec la solution ci-dessus est qu'elle copie le contenu de la structure FILE (* stdin), et non le handle FILE *. Ainsi, tout code VS2008 examinerait une structure sous-jacente différente de VS2015. Cela pourrait fonctionner si la structure ne contenait que des pointeurs, mais c'est un gros risque. Dans tous les cas, le premier problème rend cela inutile.
Le seul hack que j'ai pu imaginer est celui dans lequel __iob_func parcourt la pile d'appels pour déterminer le descripteur de fichier réel qu'ils recherchent (en fonction du décalage ajouté à l'adresse renvoyée) et renvoie une valeur calculée telle qu'elle donne la bonne réponse. C'est tout aussi insensé que cela puisse paraître, mais le prototype pour x86 uniquement (pas x64) est répertorié ci-dessous pour votre amusement. Cela a bien fonctionné dans mes expériences, mais votre kilométrage peut varier - non recommandé pour une utilisation en production!
la source
J'ai eu le même problème dans VS2015. Je l'ai résolu en compilant les sources SDL2 dans VS2015.
la source
SDL2main
et de copierSDL2main.lib
Je ne sais pas pourquoi mais:
Après l'inclusion, mais avant que votre main ne le répare d'après mon expérience
la source
Une solution plus récente à ce problème: utilisez les bibliothèques sdl les plus récentes sur
" https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/?C=M;O=D "
Ils semblent avoir résolu le problème, bien que ce ne soit que la bibliothèque 32 bits (je pense).
la source
Lier signifie ne pas fonctionner correctement. Creuser dans stdio.h de VS2012 et VS2015 ce qui suit a fonctionné pour moi. Hélas, vous devez décider si cela doit fonctionner pour l'un des {stdin, stdout, stderr}, jamais plus d'un.
la source
Mon conseil est de ne pas (essayer de) implémenter __iob_func.
Lors de la correction de ces erreurs:
libpngd.v110.lib(pngrutil.obj) : error LNK2001: unresolved external symbol ___iob_func curllib.v110.lib(mprintf.obj) : error LNK2001: unresolved external symbol ___iob_func
J'ai essayé les solutions des autres réponses, mais à la fin, le retour d'un
FILE*
tableau C ne correspond pas à un tableau de structures IOB internes de Windows. @Volker a raison de dire que cela ne fonctionnera jamais plus d'unstdin
,stdout
oustderr
.Si une bibliothèque UTILISE réellement l' un de ces flux, elle plantera . Tant que votre programme ne les oblige pas à les utiliser, vous ne le saurez jamais . Par exemple,
png_default_error
écritstderr
lorsque le CRC ne correspond pas aux métadonnées du PNG. (Normalement pas un problème digne d'un crash)Conclusion: il n'est pas possible de mélanger les bibliothèques VS2012 (Platform Toolset v110 / v110_xp) et VS2015 +, si elles utilisent stdin, stdout et / ou stderr.
Solution: recompilez vos bibliothèques qui ont des
__iob_func
symboles non résolus avec votre version actuelle de VS et un jeu d'outils de plate-forme correspondant.la source
Utilisez SDL2main.lib et SDL.lib précompilés pour la bibliothèque de votre projet VS2015: https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/sdl-visualstudio-2225.zip
la source
Je résous ce problème avec la fonction suivante. J'utilise Visual Studio 2019.
parce que l'appel de fonction défini par macro stdin, l'expression "* stdin" ne peut pas être utilisée dans l'initialiseur de tableau global. Mais l'initialisation du tableau local est possible. désolé, je suis pauvre en anglais.
la source
Pour tous ceux qui recherchent toujours une réponse là où les astuces ci-dessus n'ont pas fonctionné. La liaison statique est le moyen de résoudre ce problème. Modifiez les paramètres de votre bibliothèque d'exécution comme ci-dessous
Project properties --> C/C++ --> Code generation --> Runtime Library --> Multi-threaded Debug (/MTd) instead of /MDd
la source
J'ai réussi à résoudre le problème.
La source de l'erreur était cette ligne de code, qui se trouve dans le code source de SDLmain.
Donc, ce que j'ai fait a été de modifier le code source dans SDLmain de cette ligne aussi:
Et puis j'ai construit le SDLmain et copié et remplacé l'ancien SDLmain.lib dans mon répertoire de bibliothèque SDL2 par le nouvellement construit et édité.
Ensuite, lorsque j'ai exécuté mon programme avec SDL2, aucun message d'erreur n'est apparu et le code s'est bien déroulé.
Je ne sais pas si cela me mordra plus tard, mais donc pour tout va bien.
la source
Cela peut se produire lorsque vous créez un lien vers msvcrt.dll au lieu de msvcr10.dll (ou similaire), ce qui est un bon plan. Parce que cela vous permettra de redistribuer la bibliothèque d'exécution de votre Visual Studio dans votre package logiciel final.
Cette solution de contournement m'aide (à Visual Studio 2008):
Cet extrait de code n'est pas nécessaire pour Visual Studio 6 et son compilateur. Par conséquent, le #ifdef.
la source
Pour apporter plus de confusion dans ce fil déjà riche, je suis tombé sur le même externe non résolu sur fprintf
Même si dans mon cas c'était dans un contexte assez différent: sous Visual Studio 2005 (Visual Studio 8.0) et l'erreur se produisait dans mon propre code (le même que je compilais), pas un tiers.
Il est arrivé que cette erreur ait été déclenchée par l'option / MD dans les indicateurs de mon compilateur. Le passage à / MT a supprimé le problème. C'est bizarre car en général, la liaison statique (MT) pose plus de problème que dynamiquement (MD) ... mais juste au cas où elle sert d'autres, je la mets là.
la source
Dans mon cas, cette erreur provient de mon essai pour supprimer les dépendances à la DLL de bibliothèque d'exécution dépendante de la version MSVC (msvcr10.dll ou plus) et / ou supprimer également la bibliothèque d'exécution statique, pour supprimer l'excès de graisse de mes exécutables.
J'utilise donc / NODEFAULTLIB linker switch, mon self-made "msvcrt-light.lib" (google pour cela quand vous en avez besoin) et
mainCRTStartup()
/WinMainCRTStartup()
entries.C'est IMHO depuis Visual Studio 2015, donc je suis resté fidèle aux anciens compilateurs.
Cependant, la définition du symbole _NO_CRT_STDIO_INLINE supprime tous les tracas, et une simple application "Hello World" fait à nouveau 3 Ko de petite taille et ne dépend pas de DLL inhabituelles. Testé dans Visual Studio 2017.
la source
Collez ce code dans l'un de vos fichiers source et recréez-le. A travaillé pour moi!
#include stdio.h
FILE _iob [3];
FICHIER * __cdecl __iob_func (void) {
_iob [0] = * stdin;
_iob [0] = * stdout;
_iob [0] = * stderr;
return _iob;
}
la source