Comment utiliser VC++ fonctions intrinsèques w/o bibliothèque run-time
Je suis impliqué dans l'un de ces défis où vous essayez de produire la plus petite possible binaire, donc je suis en train de construire mon programme sans le C ou C++ bibliothèques d'exécution (RTL). Je n'ai pas de lien pour la version de la DLL ou la version statique. Je n'ai même pas #include
les fichiers d'en-tête. J'ai ce travail très bien.
Certains RTL fonctions, comme memset()
, peut être utile, j'ai donc essayé d'ajouter mon propre mise en œuvre. Il fonctionne très bien dans les versions Debug (même pour les lieux où le compilateur génère une implicite appel à memset()
). Mais dans les versions Release, j'obtiens un message d'erreur disant que je ne peut pas définir une fonction intrinsèque. Vous voyez, dans les versions Release, intrinsèque fonctions sont activées, et memset()
est intrinsèque.
J'aimerais utiliser la valeur intrinsèque pour memset()
dans ma version s'appuie, depuis c'est probablement incorporé et plus petit et plus rapide que ma mise en œuvre. Mais il me semble être dans un catch-22. Si je ne définissent pas memset()
, l'éditeur de liens se plaint qu'il est indéfini. Si je ne le définir, le compilateur se plaint que je ne peut pas définir une fonction intrinsèque.
Personne ne sait la bonne combinaison de définition, déclaration, #pragma
, et le compilateur et l'éditeur de liens indicateurs pour obtenir une fonction intrinsèque sans tirer à RTL le dessus?
Visual Studio 2008, x86, Windows XP+.
À rendre le problème un peu plus concret:
extern "C" void * __cdecl memset(void *, int, size_t);
#ifdef IMPLEMENT_MEMSET
void * __cdecl memset(void *pTarget, int value, size_t cbTarget) {
char *p = reinterpret_cast<char *>(pTarget);
while (cbTarget > 0) {
*p++ = static_cast<char>(value);
--cbTarget;
}
return pTarget;
}
#endif
struct MyStruct {
int foo[10];
int bar;
};
int main() {
MyStruct blah;
memset(&blah, 0, sizeof(blah));
return blah.bar;
}
Et je accumulation de ce genre:
cl /c /W4 /WX /GL /Ob2 /Oi /Oy /Gs- /GF /Gy intrinsic.cpp
link /SUBSYSTEM:CONSOLE /LTCG /DEBUG /NODEFAULTLIB /ENTRY:main intrinsic.obj
Si je compile avec ma mise en œuvre de memset()
, j'obtiens une erreur de compilateur:
error C2169: 'memset' : intrinsic function, cannot be defined
Si je compile sans ma mise en œuvre de memset()
, j'obtiens une erreur de l'éditeur de liens:
error LNK2001: unresolved external symbol _memset
- C'est
/GL
c'est ça le problème, voir ma réponse ci-dessous.
Vous devez vous connecter pour publier un commentaire.
Je pense que j'ai finalement trouvé une solution:
Tout d'abord, dans un fichier d'en-tête, déclarer
memset()
avec un pragma, comme suit:Qui permet à votre code d'appel de
memset()
. Dans la plupart des cas, le compilateur va inline intrinsèques version.Deuxième, dans un fichier de mise en oeuvre, de fournir une implémentation. L'astuce pour empêcher le compilateur de se plaindre de re-définir une fonction intrinsèque est d'utiliser un autre pragma premier. Comme ceci:
Cela fournit une mise en œuvre dans les cas où l'optimiseur décide de ne pas utiliser la valeur intrinsèque de la version.
La circulation inconvénient est que vous devez désactiver l'ensemble du programme d'optimisation (/GL et /LTCG). Je ne sais pas pourquoi. Si quelqu'un trouve un moyen de le faire sans la désactivation de l'optimisation globale, s'il vous plaît carillon.
void *
sont normalementstatic_cast
-s, pasreinterpret_cast
-s.void *
d'utiliser unstatic_cast
. À l'époque, je l'ai d'abord écrit ce qui en fonte à utiliser dans la situation n'est pas claire et l'objet de débats. (stackoverflow.com/questions/310451/...) je ne suis pas sûr de ce que vous entendez à propos de "tous" les cas. Il y a deux. La première est nécessaire parce que vous ne pouvez pas écrire par l'intermédiaire d'un pointeur sur void (qui est ce quememset
prend). La deuxième est de sorte que le compilateur ne pas avertir au sujet de l'attribution d'un int à un unsigned char.Je suis assez sûr qu'il y a un compilateur drapeau qui indique VC++ ne pas utiliser intrinsèques
La source de la bibliothèque runtime est installé avec le compilateur. Vous avez le choix de l'extraction de fonctions que vous voulez/besoin d', bien que souvent vous aurez à modifier en profondeur (car ils comprennent des fonctionnalités et/ou de dépendances vous ne voulez pas/besoin).
Il y a d'autres open source runtime des bibliothèques disponibles, qui pourraient avoir besoin de moins de personnalisation.
Si vous êtes vraiment sérieux à ce sujet, vous aurez besoin de savoir (et peut-être utiliser) langage d'assemblage.
Modifiées afin d'ajouter:
J'ai reçu votre code de test pour compiler et lier. Ce sont les paramètres pertinents:
C'est ce dernier qui supprime "compilateur aides" comme le haut-memset.
Modifiées afin d'ajouter:
Maintenant que c'est découplé, vous pouvez copier le code asm de memset.asm dans votre programme, il a une référence à l'échelle mondiale, mais vous pouvez le retirer. Il est assez grand de sorte qu'il est pas inline, mais si vous supprimez toutes les astuces qu'il utilise pour gagner de la vitesse, vous pourriez être en mesure de faire assez petit pour que.
J'ai pris ton exemple ci-dessus et a remplacé le
memset()
avec ceci:Il fonctionne, mais la bibliothèque de version est beaucoup plus rapide.
memset
, le inline fonction intrinsèque est inférieure à l'appel de la fonction.Je pense que vous avez à mettre de l'Optimisation, de "Réduire la Taille (/O1)" ou "Désactivé (/Od)" pour obtenir la Libération de configuration de la compilation; au moins c'est ce qu'a fait le tour pour moi avec VS 2005. Intrinsèques sont conçus pour la vitesse, donc il est logique qu'elles seraient activées pour les autres niveaux d'Optimisation (Vitesse et Complet).
Juste le nom de la fonction de quelque chose de légèrement différent.
ClearMemory()
à l'aide d'un espace de noms pour s'assurer qu'il n'entre pas en conflit avec quoi que ce soit d'autre. L'optimiseur de remplacer ma mise en œuvre deClearMemory()
avec un appel àmemset()
(avec une valeur d'un octet de 0)! Trop intelligent pour son propre bien. 🙂memset
en premier lieu (comme dans une classe d'initialiseur).Cela fonctionne bien avec VS 2015:
Ajouter l'option de ligne de commande /Oi-. Cela fonctionne parce que "Non" sur les fonctions Intrinsèques n'est pas un switch, c'est non spécifié. /Oi - et tous vos problèmes disparaissent (il devrait travailler avec l'ensemble du programme d'optimisation, mais je n'ai pas testé correctement ce).
La façon dont la "régulière" de la bibliothèque d'exécution ne c'est par la compilation d'un fichier d'assemblage avec une définition de memset et de faire le lien dans la bibliothèque d'exécution (Vous pouvez trouver l'assemblée fichier dans ou autour de C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\intel\memset.asm). Ce genre de chose fonctionne bien, même avec l'ensemble du programme d'optimisation.
Également noter que le compilateur utilisera uniquement le memset intrinsèque dans certains cas (lorsque la taille est constante et les petits?). Il sera généralement utiliser la fonction memset fournies par vous, alors vous devriez probablement utiliser la fonction optimisée en memset.l'asm, à moins que vous allez écrire quelque chose de tout aussi optimisé.