Comment utiliser VC++ fonctions intrinsèques avec/sans bibliothèque de temps d'exécution

je suis impliqué dans l'un de ces défis où vous essayez de produire le plus petit binaire possible, donc je construis mon programme sans les bibliothèques d'exécution C ou c++ (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.

certaines fonctions RTL, comme memset(), peut être utile, donc j'ai essayé d'ajouter ma propre implémentation. Il fonctionne très bien dans les constructions de débogage (même pour les endroits où le compilateur génère un implicite appel memset()). Mais dans Release builds, je reçois une erreur disant que je ne peux pas définir une fonction intrinsèque. Vous voyez, dans Release builds, les fonctions intrinsèques sont activées, et memset() est un intrinsèque.

j'aimerais utiliser la valeur intrinsèque pour memset() dans ma version construit, car il est probablement inlined et plus petit et plus rapide que mon implémentation. Mais j'ai l'air d'être un dans catch-22. Si je n'ai pas de définir memset(), le linker se plaint qu'il est indéfini. Si je le définis, le compilateur se plaint que je ne puisse pas définir une fonction intrinsèque.

quelqu'un sait-il le droit de la combinaison de la définition, de la déclaration #pragma, et les indicateurs de compilateur et de linker pour obtenir une fonction intrinsèque sans tirer dans RTL overhead?

Visual Studio 2008, x86, Windows XP+.

pour 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 construis comme ceci:

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 mon implémentation de memset(), j'obtiens une erreur du compilateur:

error C2169: 'memset' : intrinsic function, cannot be defined

si je compilais ceci sans ma mise en oeuvre de memset(), j'obtiens une erreur de l'éditeur de liens:

error LNK2001: unresolved external symbol _memset
30
demandé sur Adrian McCarthy 2010-05-30 18:16:26

6 réponses

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:

extern "C" void * __cdecl memset(void *, int, size_t);
#pragma intrinsic(memset)

qui permet à votre code d'appeler memset(). Dans la plupart des cas, le compilateur alignera la version intrinsèque.

deuxièmement, dans un fichier de mise en oeuvre séparé, fournir une mise en oeuvre. 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:

#pragma function(memset)
void * __cdecl memset(void *pTarget, int value, size_t cbTarget) {
    unsigned char *p = static_cast<unsigned char *>(pTarget);
    while (cbTarget-- > 0) {
        *p++ = static_cast<unsigned char>(value);
    }
    return pTarget;
}

ceci fournit une implémentation pour les cas où l'optimiseur décide de ne pas utiliser la version intrinsèque.

l'inconvénient est que vous devez désactiver l'optimisation du programme entier (/GL et /LTCG). Je ne sais pas pourquoi. Si quelqu'un trouve un moyen de le faire sans désactiver l'optimisation globale, s'il vous plaît répondez.

19
répondu Adrian McCarthy 2012-01-16 17:47:26
  1. je suis presque sûr qu'il y a un drapeau de compilateur qui dit à VC++ de ne pas utiliser intrinsics

  2. La source de la bibliothèque runtime est installé avec le compilateur. Vous avez le choix d'extraire les fonctions que vous voulez/devez, bien que souvent vous devrez les modifier en profondeur (parce qu'elles incluent des fonctionnalités et/ou des dépendances que vous ne voulez pas/ne devez pas).

  3. il existe aussi d'autres bibliothèques d'exécution open source disponibles, qui pourraient besoin de moins de personnalisation.

  4. si vous êtes vraiment sérieux à ce sujet, vous aurez besoin de connaître (et peut-être utiliser) le langage d'assemblage.

Edité pour ajouter:

j'ai votre nouveau code de test à compiler et relier. Ce sont les paramètres pertinents:

Enable Intrinsic Functions: No
Whole Program Optimization: No

c'est le dernier qui supprime les "helpers de compilateurs" comme le memset intégré.

Edité pour 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 globale, mais vous pouvez supprimer cela. Il est assez grand pour qu'il soit 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 votre exemple ci-dessus et remplacé le memset() avec ceci:

void * __cdecl memset(void *pTarget, char value, size_t cbTarget) {
    _asm {
    push ecx
    push edi

    mov al, value
    mov ecx, cbTarget
    mov edi, pTarget
    rep stosb

    pop edi
    pop ecx
    }
    return pTarget;
}

cela fonctionne, mais la version de la Bibliothèque est beaucoup plus rapide.

5
répondu egrunin 2010-05-31 20:01:27

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).

1
répondu Luke 2010-05-30 18:04:37

il suffit de nommer la fonction quelque chose de légèrement différent.

0
répondu Puppy 2010-05-31 17:35:51

cela fonctionne certainement 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 interrupteur, il n'est pas spécifié. /Oi - et tous vos problèmes disparaissent (cela devrait fonctionner avec l'optimisation du programme entier, mais je n'ai pas correctement testé cela).

0
répondu Solocle 2017-02-12 20:48:03

la façon dont la bibliothèque d'exécution" régulière " le fait est en compilant un fichier d'assemblage avec une définition de memset et en le reliant dans la bibliothèque d'exécution (vous pouvez trouver le fichier d'assemblage dans ou autour C:\Program fichiers\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.

notez aussi que le compilateur n'utilisera le memset intrinsèque que dans certains cas particuliers (lorsque la taille est constante et petite?). Il généralement utiliser la fonction memset fournies par vous, alors vous devriez probablement utiliser la fonction optimisée en memset.asm, à moins que tu n'écrives quelque chose d'aussi optimisé.

-1
répondu namey 2016-06-06 23:33:35