2017-05-05 1 views
3

L'objectif est d'être en mesure de le faire:opération Bitwise, le déplacement d'un bit de report

struct.pack('!H', x) 

Mais si x est supérieure à 65535 alors cela ne fonctionne pas pour des raisons évidentes.
Je ne suis pas un assistant avec la manipulation de bits, mais j'ai compris que les opérations << perdraient des bits décalés. Mais je n'ai aucune idée comment extraire un ou plusieurs bits porteurs de la chaîne binaire/octets et ajouter la valeur de report à l'ensemble de deux octets traînant les octets porteurs.

Et j'ai besoin de parcourir la chaîne d'octets par 2 octets à chaque fois et les additionner contre les deux octets précédents. Parfois, cela va générer une valeur supérieure à 65535 - c'est là que j'ai besoin d'extraire le bit de report du résultat - et effectuer une opération + sur le résultat avec le bit de retenue lui-même (voir l'image ci-dessous).

C'est ce que je suis en train d'accomplir: (. Dans ce cas, le bit de transport était seul, et les 2 octets de fin recevrais +1 suite) enter image description here

Et ce que je « ai jusqu'à présent:

from struct import unpack, pack 
from binascii import * 

even_bytes_string = b'\x45\x00\x00\x3c\x1c\x46\x40\x00\x40\x06\xac\x10\x0a\x63\x‌​ac\x10\x0a\x0c' 
result = None 
for i in range(0, len(even_bytes_string)-1,2): 
    if not result: 
     result = unpack('!H', even_bytes_string[i:i+2])[0] 
     continue 

    result += unpack('!H', even_bytes_string[i:i+2])[0] 
    if result > 65535: 
     # Got a carry bit. 
     pass 

    print(result) 
    print(pack('!H', result)) 

J'ai littéralement aucune idée comment faire cette tâche assez simple, sans convertir le résultat d'une opération d'ajout dans la représentation binaire réelle sous forme de chaîne (11001...). Et puis faites la manipulation de la chaîne s = s[-16:]+s[:-16] (simplifié à l'extrême), pour finalement le convertir en un ensemble de 2 octets. Il ne semble pas pratique, rapide ou très "correct". J'espère que l'un d'entre vous connaîtra la manipulation des bits en Python qui pourrait me dire quelle est la bonne façon de le faire. Il doit y en avoir.

Un peu plus confus image de ce que je suis en train d'accomplir (de garder résultat à 2 octets, coupant les bits transportant et en les ajoutant au résultat comme une valeur « séparée ».): enter image description here

+0

qu'attendez-vous si le dernier bit est 1 et non 0? – Tryph

+0

@Tryph Je viens de réaliser que je suis simplement supposé ajouter les bits porteurs (peut-être plusieurs) aux deux ensembles d'octets. Donc, ma question a besoin d'une mise à jour. – Torxed

+0

Peut-être que je pourrais utiliser 'carry = struct.pack ('! I', résultat) [: 2]'? Encore une fois, les coutures sont peu pratiques mais seraient mieux que la conversion en une représentation binaire et la manipulation de chaînes! – Torxed

Répondre

1

Le processus est juste (x & 0xFFFF) + (x >> 16). L'opération << n'a pas besoin d'être impliquée. Voici une implémentation du worked example vous citez:

def addwrap16(a, b): 
    c = a + b 
    w = (c & 0xFFFF) + (c >> 16) 
    print(' {:04x} -> {:016b}'.format(a, a)) 
    print(' {:04x} -> {:016b}'.format(b, b)) 
    print('{:05x} -> {:017b}'.format(c, c)) 
    print(' {:04x} -> {:016b}'.format(w, w)) 
    print('') 
    return w 

import struct, functools 
even_bytes_string = b'\x45\x00\x00\x3c\x1c\x46\x40\x00\x40\x06\xac\x10\x0a\x63\xac\x10\x0a\x0c' 
vals = struct.unpack('!' + 'H' * (len(even_bytes_string) // 2), even_bytes_string) 
result = functools.reduce(addwrap16, vals) 

qui crache sur les éléments suivants:

4500 -> 0100010100000000 
003c -> 0000000000111100 
0453c -> 00100010100111100 
453c -> 0100010100111100 

453c -> 0100010100111100 
1c46 -> 0001110001000110 
06182 -> 00110000110000010 
6182 -> 0110000110000010 

6182 -> 0110000110000010 
4000 -> 0100000000000000 
0a182 -> 01010000110000010 
a182 -> 1010000110000010 

a182 -> 1010000110000010 
4006 -> 0100000000000110 
0e188 -> 01110000110001000 
e188 -> 1110000110001000 

e188 -> 1110000110001000 
ac10 -> 1010110000010000 
18d98 -> 11000110110011000 
8d99 -> 1000110110011001 

8d99 -> 1000110110011001 
0a63 -> 0000101001100011 
097fc -> 01001011111111100 
97fc -> 1001011111111100 

97fc -> 1001011111111100 
ac10 -> 1010110000010000 
1440c -> 10100010000001100 
440d -> 0100010000001101 

440d -> 0100010000001101 
0a0c -> 0000101000001100 
04e19 -> 00100111000011001 
4e19 -> 0100111000011001 
+0

Le '' 'était juste un exemple de bitshifting que j'espérais pouvoir être utile, mais j'ai rapidement découvert que ce n'était pas le cas. Les opérations '>>' ou '|' ne le seraient pas non plus. Cela semble faire l'affaire! :) – Torxed

+0

Suivre manuellement les valeurs que j'attendais en faisant des calculs dans ma tête, en utilisant ma solution et la vôtre - ils arrivent tous à la même conclusion. Et il semble que ce soit un en-tête de total de contrôle du réseau en train de regarder dans tcpdump, donc je suis plus que satisfait de cette solution plus efficace! Un grand merci pour la réponse, je vois même la logique pourquoi ça marche :) – Torxed

0

Ok donc ce n'est pas la solution la plus élégante, et pas sûr qu'il est réellement précis, mais il ne casse pas struct.pack() au moins.

Sur la base d'une simple question par @Tryph, ce que je suis venu avec un travail autour de:

from struct import unpack, pack 
from binascii import * 

even_bytes_string = b'\x45\x00\x00\x3c\x1c\x46\x40\x00\x40\x06\xac\x10\x0a\x63\x‌​ac\x10\x0a\x0c' 
result = None 
for i in range(0, len(even_bytes_string)-1,2): 
    if not result: 
     result = unpack('!H', even_bytes_string[i:i+2])[0] 
     continue 

    result += unpack('!H', even_bytes_string[i:i+2])[0] 
    if result > 65535: 
     tmp = pack('!I', result) 
     carry = unpack('!H', tmp[:2])[0] 
     result = unpack('!H', tmp[2:])[0]+carry 

    print(result) 
    print(pack('!H', result)) 

traite simplement le nombre plus grand comme Int au lieu de Short, cela me permet d'obtenir les deux octets qui précèdent sont reportés, et ajoutent les octets des deux octets suivants. Ce n'est pas élégant, mais ça marche probablement?