9
votes

Pliage constant complexe de GCC

Il semble que GCC a une limitation de pliage constant complexe. Voici un exemple:

static inline unsigned int DJBHash(const char *str)
{
   int i;
   unsigned int hash = 5381;

   for(i = 0; i < strlen(str); i++)
   {
      hash = ((hash << 5) + hash) + str[i];   
   }

   return hash;
}

int f(void)
{   
    return DJBHash("01234567890123456");
}


12 commentaires

Il y a probablement une option dans GCC qui vous permet de définir un seuil où il décidera de déranger quelque chose. Le déroulement constant est un processus potentiellement infini. En outre, décider si le déroulement ou non se terminera jamais est probablement le problème d'arrêt.


@Mystici Mais je n'ai pas pu trouver quoi que ce soit lié au pliage constant. J'ai essayé de changer le paramètre de boucle déroulant max-déroulement-fois mais cela ne semble avoir aucun effet.


Ensuite, il n'ya probablement pas beaucoup que vous pouvez faire. Il n'y a que tant que vous pouvez compiler sur un compilateur à faire. Et cela pousse certainement les limites. À un moment donné, vous devez être explicite. Peut-être que C ++ TMP pourrait être capable de le faire. Je ne suis pas sûr cependant.


En C ++, vous pourriez le calculer en compacte avec consexpr


BTW, optimiseur peut convertir 33 * hachage pour déplacer et ajouter en soi.


FWIW, CLANG (SVN de quelques jours) Il y a quelques jours) Le pliage constant est-il fin avec une chaîne de longueur 70.


Ahahahaha, j'ai totalement déraillé cette question en appâtant tout le monde à poster des réponses à C ++ au lieu de C.: D


@ Mysticial, très intéressant Comment une question agnostique linguistique sur la capacité d'un compilateur particulier (GCC) est devenue un forum pour préconiser les fonctionnalités C ++. Les gars c'était une question sur l'optimisation du compilateur et non sur la manière de forcer l'optimisation dans cette langue ou cette langue. Je peux probablement venir avec un préprocesseur écrit à Perl qui aurait au tour. Mais je ne ferais pas ça, ce n'était pas la question.


@Jensgustedt être juste, ce n'était pas intentionnel. Tout ce que j'ai dit était que cela pourrait être possible avec C ++ TMP. Ensuite, j'ai demandé à ce sujet dans le chat. Le résultat était que tout le monde a versé pour répondre avec C ++. La question n'a également eu aucune langue à la balise pour commencer. J'ai ajouté la balise C parce que cela ressemblait à c et il n'y avait pas de code spécifique C ++.


@ Mysticial, bien sûr, je ne voudrais pas blâmer vous , mais je viens de trouver cela intéressant à quel point une telle question est facilement monopolisée par des personnes du camp c ++. Comme vous le dites, la question est définitivement c, non C ++ en vue.


@Amirgonnen Vous voudrez peut-être clarifier la langue que vous avez autorisée à utiliser (C ou C ++). Puisqu'il semble être un peu un différend sur les balises sur votre question. Je l'ai initialement marqué C puisqu'il n'avait rien de C ++, mais la plupart des réponses que vous avez obtenues sont C ++.


@ Mysticial J'ai ajouté une clarification. Les modèles / Constexpr répondent sont intéressants mais malheureusement, ils ne m'aideront pas dans mon cas. J'ai été surpris de savoir comment les gens se sont autorisés à supprimer librement et à ajouter des balises à ma question (par exemple, supprimer la balise GCC lorsque "GCC" fait partie du titre ...)


4 Réponses :


1
votes

Pas une réponse, juste un autre point de données.

La mise en œuvre suivante est encore pire. GCC 4.7.3 applique correctement TCO pour transformer cette implémentation en une boucle, mais elle n'évalue que "0" à la date de compilation! P>

static inline unsigned int DJBHash2(const char *str, unsigned int hash) {
   return *str ? DJBHash2(str + 1, 33 * hash + *str) : hash; }


0 commentaires

3
votes

Peut-être que C ++ TMP pourrait être capable de le faire. Je ne suis pas sûr de cependant.

Il est possible si cela ne vous dérange pas d'utiliser des listes littérales de caractères variadiques au lieu de littérales de chaîne: xxx

Ideone Live Demo


1 commentaires

Vous pouvez utiliser boost :: mpl :: string .



9
votes

Voici une version utilisant consexpr code>. Il est légèrement différent des autres à un seul respect - être récursif, il était plus facile de récupérer la corde à l'avant, pour ainsi dire. Par exemple, la valeur qu'il donne pour "ABC" sera ce que vous attendez normalement de "CBA" à la place. Je ne pense pas que cela devrait faire une réelle différence d'utilisation, tant que vous utilisez l'un ou l'autre de manière cohérente (mais étant donné les aléas de hachage, je pourrais me tromper à ce sujet).

Il évalue à la compilation - Par exemple, nous pouvons utiliser les résultats comme étiquettes dans un interrupteur p> p> xxx pré>

évidemment, il pourrait y avoir des collisions, donc vous ne seriez généralement pas 'T veut l'utiliser comme étiquettes de déclaration de cas - je l'ai surtout fait pour forcer une situation dans laquelle elle ne voudrait pas compiler si le résultat n'était pas une constante de temps de compilation. P>

EDIT: Si vous Soin de l'algorithme de hachage étant "correct", je suppose que cela est plus précis (grâce à @ABYX): P>

unsigned constexpr const_hash(char const *input, unsigned hash = 5381) {
    return *input ?
        const_hash(input + 1, hash * 33 + static_cast<unsigned>(*input)): 
        hash;
}


5 commentaires

Vous pouvez obtenir le résultat correct en utilisant une fonction d'assistance récursive de la queue, voir ma réponse.


@Fredoverflow: Ouais, vous pouvez, mais je ne suis pas sûr que cela rend suffisamment de différence pour justifier le travail / code supplémentaire.


Pourquoi il y a le premier static_cast ?


La version de la queue récursive n'a pas besoin d'une fonction d'assistance. Il ressemble exactement à @ Adamburry's djbhash2 , mais le hachage doit avoir la valeur par défaut = 5381 . Et il y a une raison pour laquelle cette version est meilleure. Lorsque vous utilisez const_hash en exécution, il fonctionnera plus vite et ne mangera pas de pile. Lien


Upvoted. Notez que ce code aura une durée de vie courte: dès que c ++ 14 consexpr (déjà disponible dans Clang 3.4 svn) devient plus largement disponible, vous pouvez utiliser ma réponse.



7
votes

L'OP est intéressé par le pliage constant en C, mais juste pour son frère C ++: En C ++ 14, vous pouvez simplement mettre consexpr devant les deux fonctions et modifier la boucle à Pour compenser strlen () ne pas être consexpr xxx

Exemple live à l'aide de clang 3.4 svn avec -std = c ++ 1y > NOTE : La mise en œuvre de la collision actuelle ne fonctionne pas correctement avec un tandis que (* str! = '\ 0') . Au lieu de cela, une boucle finie de 512 avec une condition de retour à l'intérieur fait le travail.


3 commentaires

Dans le cas de Constexpr, comment CLANG calcula-t-il la valeur finale? En interprétant directement l'AST ou le JIT compilant la fonction?


@Stringer le premier, la langue grearsntees que h est évaluée avant de lancer le programme


Excusez-moi, mais en ligne est redondant sur Constexpr, car cela implique que cela implique implicitement.