2017-08-09 3 views
2

Pour une partie d'une tâche plus importante, on m'a demandé d'implémenter une fonction qui retourne un bit arbitraire dans un entier. Le hic, c'est que le "entier" pourrait être n'importe lequel des types entiers par défaut dans c, de int8_t à uint64_t, et je ne sais pas lequel il sera. (En fait, mon code a été testé sur tous ces types)Déplacement avec uint64_t ne fonctionnant pas comme prévu

Ce fut ma tentative du problème:

//NOTE: g_int is the generic integer, it's typedef'd in a .h file 
g_int flip_bit(g_int b, uint8_t i){ 
    //Code that makes sure i is a valid amount to shift by, there's a macro 
    //that defines the upper bound of i in a .h file. 
    g_int flipped = b^(1<<i); 
    return flipped; 
} 

Ce code XOR bit i e en b avec 1, et les autres bits dans b avec 0. Cela devrait renverser le bit i tout en laissant le reste inchangé. Satisfait de cela, j'ai testé mon code sur toutes ces différentes tailles d'entiers, puis je l'ai activé. Cependant, je n'ai pas testé suffisamment, car mon code a échoué à la fois sur int64_t et sur uint64_t. Qu'est-ce que j'ai fait de mal pour int64_t et uint64_t, et y a-t-il quelque chose que je puisse faire pour que ma méthode fonctionne sans la changer complètement?

+0

Bien sûr, je peux le modifier. générique n'était pas le nom réel du type dans l'affectation, je l'ai juste changé rapidement afin d'indiquer sa signification. Désolé pour la confusion. – UnknowableIneffable

+0

Comment 'g_int' est-il défini dans le fichier .h? C'est toujours pareil tout au long d'une construction? Cela peut affecter la façon dont 'flip_bit()' peut être utilisé. – chux

+0

Oui, désolé. Je voulais dire que lorsque mon code est testé, il y a un tas de différents fichiers .h qui le testent avec le même nom, testé un à la fois, avec tous ces différents types d'entiers pour chacun. Ma méthode doit fonctionner pour chacun d'eux. – UnknowableIneffable

Répondre

5

Ce problème est dû au type de 1, qui est int (qui a 32 bits sur une machine raisonnable). Cela signifie que l'exécution du décalage (1<<i) pour des valeurs supérieures ou égales à 32 entraînera un comportement indéfini.

Cela peut être fixé simplement par coulée 1 à taper g_int avant d'effectuer le déplacement:

g_int flip_bit(g_int b, uint8_t i){ 
    g_int flipped = b^(((g_int)1)<<i); 
    return flipped; 
} 
+3

La seule correction est que le décalage au-delà de la largeur de l'entier est * un comportement non défini * (non nul). http://port70.net/~nsz/c/c11/n1570.html#6.5.7p4 –

+0

Merci, je vais le mettre à jour. – UnknowableIneffable

+1

* comportement indéfini * est différent de "valeur indéfinie". Tout peut arriver, pas seulement une valeur inattendue. –