2008-11-06 4 views
3

J'ai un code qui ressemble à:Se débarrasser du décalage gcc par avertissement négatif

template<unsigned int A, unsigned int B> 
int foo() { 
    int v = 1; 
    const int x = A - B; 
    if (x > 0) { 
    v = v << x; 
    } 
    bar(v); 
} 

gcc se plaindra de x étant négatif pour certaines instanciations de A, B; cependant, j'effectue une vérification pour m'assurer qu'il est non négatif. Quel est le meilleur moyen de contourner cela? Je sais que je peux lancer x pour être unsigned int mais cela entraînera des avertissements à propos de x étant plus grand que la largeur de v (puisqu'il émet un nombre négatif pour être positif). Je sais qu'il existe une solution de rechange qui consiste à créer une nouvelle fonction shift, mais je voudrais éviter cela si possible.

Répondre

3

Depuis A et B sont connus au moment de la compilation, non seulement pouvez-vous vous débarrasser de votre avertissement, mais vous pouvez également vous débarrasser d'une exécution if, sans moulages, comme ceci:

#include <iostream> 
using namespace std; 

template< unsigned int A, unsigned int B > 
struct my 
{ 
    template< bool P > 
    static void shift_if(int &); 

    template<> 
    static void shift_if<false>(int &) {} 

    template<> 
    static void shift_if<true>(int & v) { v <<= A - B; } 

    static void op(int & v) { shift_if< (A > B) >(v); } 
}; 

template< unsigned int A, unsigned int B > 
int foo() 
{ 
    int v = 1; 
    my< A, B >::op(v); 
    return v; 
} 

int main() { 
    cout << foo< 1, 3 >() << endl; 
    cout << foo< 3, 1 >() << endl; 
    cout << foo< 300, 1 >() << endl; 
    cout << foo< 25, 31 >() << endl; 
    return 0; 
} 
+0

Une très bonne solution. mais il faudrait modifier le problème (A - B> = 32). BTW, le si serait probablement exclu de toute façon puisque le compilateur peut détecter que cela n'arrivera jamais. –

+0

@Evan Teran, Merci! J'ai remarqué le problème du passage à la ligne, mais le code original de l'OP l'a laissé emballer, donc j'ai supposé que c'était ce qu'il voulait. Je pense que vous avez raison sur l'optimisation du compilateur mais dans ma version, l'expression A - B n'est pas signée, évitant ainsi un avertissement. – jwfearn

+0

Idéalement, je voudrais que le code me prévienne si je changeais trop si ce nombre était positif et ne me prévient pas du tout s'il était négatif (puisqu'il ne serait pas exécuté). Je suppose qu'il n'y a aucun moyen de contourner cela, mais de cette façon. Bon à savoir. –

0

Est-ce que cela fonctionnerait?

const short unsigned int x = A - B; 

Il est couper beaucoup plus de bits que le besoin d'être coupé, mais si vos valeurs de A - B sont assez petits ...

+0

Pour être plus concret: je 'a == 25 'et' B == 31'. Cela me donne «x == -6» qui ressemble à «111 ... 11010» et tronquer cela me donnerait quand même un nombre plutôt grand. –

2

pourquoi ne pas faire x type unsigned char et de le jeter ? vous n'avez sûrement pas besoin de changer plus de 255 bits?

const unsigned char x = static_cast<unsigned char>(A - B); 

ou peut-être utiliser le masquage pour faire en sorte que le changement est dans les limites comme celui-ci:

const unsigned int x = static_cast<unsigned int>(A - B) & 0x1f; // limit A-B to have a range of (0 - 31) 

EDIT:

en réponse au commentaire est ici une idée:

template<unsigned int A, unsigned int B> 
int foo() { 
    int v = 1; 
    const int x = A - B; 
    if (x > 0) { 
    v = v << (static_cast<unsigned int>(x) & 0x1f); 
    } 
    bar(v); 
} 

REMARQUE: vous pouvez remplacer 0x1f avec quelque chose comme: (CHAR_BIT * sizeof (T) - 1)

EDIT: en réponse au dernier commentaire, ce code ne délivre aucun avertissement avec la compilation: g ++ -W -Wall -ansi -pedantic test.cc -o Test

#include <iostream> 

template<unsigned int A, unsigned int B> 
int foo() { 
    int v = 1; 
    const int x = A - B; 
    if (x > 0) { 
    v = v << (static_cast<unsigned int>(x) & 0x1f); 
    } 
    return v; 
} 

int main() { 
    std::cout << foo<1, 3>() << std::endl; 
    std::cout << foo<3, 1>() << std::endl; 
    std::cout << foo<300, 1>() << std::endl; 
    std::cout << foo<25, 31>() << std::endl; 
} 
+0

Je crois que si le côté droit était négatif, il le ferait passer à '' int 'non signé qui le rendrait positif. Je ne veux pas faire exécuter le code si le résultat de 'A-B' est négatif. –

+0

Puisqu'il connaît les valeurs au moment de la compilation, tout nombre supérieur à 32 signalera un autre avertissement concernant le décalage d'un nombre supérieur à la largeur du type. Donc, même si cela résout effectivement le problème négatif, il soulèvera ce deuxième avertissement. –

+0

Je limite la valeur à 0-32, donc il ne devrait y avoir aucun avertissement –