如何对64位数据进行位操作并输出到dll中的C函数

San*_*ndy 0 python string bit-manipulation

我想将表示寄存器的压缩数组传递给接受a的C函数(在DLL中)char *.这是我到目前为止的代码:

from ctypes import * 
class BitField():
    def __init__(self,position,size):
        self.position = position
        self.size = size

class Reg1(BitField):
    self.dll = "win32.dll"
    self.B6 = BitField(self,58,6)
    self.B5 = BitField(self,54,4)
    self.B4 = BitField(self,48,6)
    self.B3 = BitField(self,36,12)
    self.B2 = BitField(self,24,12)
    self.B1 = BitField(self,16,8)
    self.B0 = BitField(self,0,16)

pack_register(Reg1,(expects a tuple)):
   pass    # created a stub , need help on this   
#I want to pack the to 64 bit data, by padding all other zero's, 
#if none of bit #fields specified by user.

obj = Reg1()
obj.B5 = 4
obj.B4 = 12
obj.B0 = 70
charBuffer = create_string_buffer(64)
packed_value =pack_register(Reg1,(B5,B4,B0)) 
charBuffer  = packed_value
obj.dll.createBuff(charBuffer) # accepting a character pointer
Run Code Online (Sandbox Code Playgroud)

这是win32.dll函数(在C中)

int createBuff (char * charBuffer){
   print charBuffer
}
Run Code Online (Sandbox Code Playgroud)

从代码中的注释可以看出,我不知道如何将寄存器打包成64位.我也有32位和128位寄存器.

如何打包寄存器并以合适的格式输出它以传递给我期望的C函数char *

PM *_*ing 5

此代码创建一个类,使您可以使用字段名称读取和写入位域.它没有记ctypes在心里,但你仍然觉得它很有用.

#!/usr/bin/env python

""" A bit field class

    See http://stackoverflow.com/q/31960327/4014959

    Written by PM 2Ring 2015.08.12
"""

class BitFields(object):
    """ A bit field class

        fieldwidth is a tuple or list containing the
        bit width of each field, from least significant
        to most significant.
    """
    def __init__(self, totalwidth, fieldwidths):
        if sum(fieldwidths) != totalwidth:
            raise ValueError, "Field width error"

        self.fieldwidths = fieldwidths
        self.num_fields = len(fieldwidths)

        #Calculate field offsets
        self.offsets = []
        pos = 0
        for w in fieldwidths:
            self.offsets.append(pos)
            pos += w

        #Set up bitfield attribute names
        self.field_names = ['b' + str(i) for i in range(self.num_fields)]
        self.clear()

    #Set all fields to zero
    def clear(self):
        for f in self.field_names:
            setattr(self, f, 0)

    #A generator expression of all the field values
    def _all_fields(self):
        return (getattr(self, f) for f in self.field_names)

    def __str__(self):
        return ', '.join(['%s: 0x%x' % (f, v) 
            for f, v in zip(self.field_names, self._all_fields())])

    #Get the register value as an int
    @property
    def value(self):
       return sum(v<<p for v, p in zip(self._all_fields(), self.offsets))

    #Set field values 
    def regset(self, **kwargs):
        for f, v in kwargs.items():
            setattr(self, f, v)

#Test
fields = (16, 8, 12, 12, 6, 4, 6)
reg = BitFields(64, fields)

#Set some fields by attribute
reg.b0 = 10
reg.b1 = 1
reg.b2 = 3

#Print the register using its __str__ method
print reg

#Print a single field
print reg.b1

#Print the current value of the register in decimal and as a hex string
v = reg.value
print v, hex(v)

#Reset all fields to zero
reg.clear()
print reg

#Set some fields by keyword
reg.regset(b0=7, b1=3, b2=1)
print reg

#Set some fields using a dict
field_dict = {'b0':5, 'b3':0xa, 'b4':0xf}
reg.regset(**field_dict)
print reg
Run Code Online (Sandbox Code Playgroud)

产量

b0: 0xa, b1: 0x1, b2: 0x3, b3: 0x0, b4: 0x0, b5: 0x0, b6: 0x0
1
50397194 0x301000a
b0: 0x0, b1: 0x0, b2: 0x0, b3: 0x0, b4: 0x0, b5: 0x0, b6: 0x0
b0: 0x7, b1: 0x3, b2: 0x1, b3: 0x0, b4: 0x0, b5: 0x0, b6: 0x0
b0: 0x5, b1: 0x3, b2: 0x1, b3: 0xa, b4: 0xf, b5: 0x0, b6: 0x0
Run Code Online (Sandbox Code Playgroud)

这是一个简单的Python 2 to_bytes()函数.

def to_bytes(n, width):
    b = bytearray(width)
    for i in range(width-1, -1, -1):
        b[i] = n & 0xff
        n >>= 8
        if n == 0:
            break
    return bytes(b)

n = 0x8182838485868788
print repr(to_bytes(n, 8))
Run Code Online (Sandbox Code Playgroud)

产量

'\x81\x82\x83\x84\x85\x86\x87\x88'
Run Code Online (Sandbox Code Playgroud)

这是带有新方法的类的略微修改版本.setvalue(),它允许您从整数设置寄存器的值.在构造函数中调用此方法,因此您现在可以传递一个可选的整数来初始化寄存器.如果没有初始值传递给构造函数,则寄存器初始化为零,如前所述.

class BitFields(object):
    """ A bit field class

        fieldwidth is a tuple or list containing the
        bit width of each field, from least significant
        to most significant.
    """
    def __init__(self, totalwidth, fieldwidths, value=0):
        if sum(fieldwidths) != totalwidth:
            raise ValueError, "Field width error"

        self.fieldwidths = fieldwidths
        self.num_fields = len(fieldwidths)

        #Calculate field offsets
        self.offsets = []
        pos = 0
        for w in fieldwidths:
            self.offsets.append(pos)
            pos += w

        #Set up bitfield attribute names
        self.field_names = ['b' + str(i) for i in range(self.num_fields)]

        #Initialize
        self.setvalue(value)

    #Set all fields to zero
    def clear(self):
        for f in self.field_names:
            setattr(self, f, 0)

    #A generator expression of all the field values
    def _all_fields(self):
        return (getattr(self, f) for f in self.field_names)

    def __str__(self):
        return ', '.join(['%s: 0x%x' % (f, v) 
            for f, v in zip(self.field_names, self._all_fields())])

    #Get the register value as an int
    @property
    def value(self):
       return sum(v<<p for v, p in zip(self._all_fields(), self.offsets))

    #Set field values 
    def regset(self, **kwargs):
        for f, v in kwargs.items():
            setattr(self, f, v)

    #Set the register from an int 
    def setvalue(self, value):
        for f, w in zip(self.field_names, self.fieldwidths):
            #print f, w
            mask = (1<<w) - 1
            v = value & mask
            value >>= w
            setattr(self, f, v)


#Test
fields = (16, 8, 12, 12, 6, 4, 6)
reg = BitFields(64, fields)

#Set some fields by attribute
reg.b0 = 10
reg.b1 = 1
reg.b2 = 3

#Print the register using its __str__ method
print reg

#Print a single field
print reg.b1

#Print the current value of the register in decimal and as a hex string
v = reg.value
print v, hex(v)

#Reset all fields to zero
reg.clear()
print reg

#Set some fields by keyword
reg.regset(b0=7, b1=3, b2=1)
print reg

#Set some fields using a dict
field_dict = {'b0':5, 'b3':0xa, 'b4':0xf}
reg.regset(**field_dict)
print reg

#Set the register from an int or long
n = 0x111133337777ffff
reg = BitFields(64, fields, n)
print reg

v = reg.value
print v, hex(v), n == v

n = 0x123456789abcdef0
reg.setvalue(n)
print reg

v = reg.value
print v, hex(v), n == v

import random

print 'Testing .setvalue()...'
for _ in xrange(50000):
    n = random.randint(0, (1<<64) - 1)
    reg.setvalue(n)
    v = reg.value
    assert v == n, (n, v)
print 'OK'
Run Code Online (Sandbox Code Playgroud)

产量

b0: 0xa, b1: 0x1, b2: 0x3, b3: 0x0, b4: 0x0, b5: 0x0, b6: 0x0
1
50397194 0x301000a
b0: 0x0, b1: 0x0, b2: 0x0, b3: 0x0, b4: 0x0, b5: 0x0, b6: 0x0
b0: 0x7, b1: 0x3, b2: 0x1, b3: 0x0, b4: 0x0, b5: 0x0, b6: 0x0
b0: 0x5, b1: 0x3, b2: 0x1, b3: 0xa, b4: 0xf, b5: 0x0, b6: 0x0
b0: 0xffff, b1: 0x77, b2: 0x377, b3: 0x333, b4: 0x11, b5: 0x4, b6: 0x4
1229820469389557759 0x111133337777ffffL True
b0: 0xdef0, b1: 0xbc, b2: 0x89a, b3: 0x567, b4: 0x34, b5: 0x8, b6: 0x4
1311768467463790320 0x123456789abcdef0L True
Testing .setvalue()...
OK
Run Code Online (Sandbox Code Playgroud)