Search code examples
pythonc++cctypesunsigned-integer

C - Signed and Unsigned integer


I'm delving into C because I need to import ctypes library to python to allow for keyboard control. I'm trying to learn how the following code works:

import ctypes
import time

SendInput = ctypes.windll.user32.SendInput

# C struct redefinitions 
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_ulong),
                ("time", ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(ctypes.Structure):
    _fields_ = [("uMsg", ctypes.c_ulong),
                ("wParamL", ctypes.c_short),
                ("wParamH", ctypes.c_ushort)]

class MouseInput(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long),
                ("dy", ctypes.c_long),
                ("mouseData", ctypes.c_ulong),
                ("dwFlags", ctypes.c_ulong),
                ("time",ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(ctypes.Structure):
_fields_ = [("type", ctypes.c_ulong),
            ("ii", Input_I)]

# Actuals Functions

def PressKey(hexKeyCode):

    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( hexKeyCode, 0x48, 0, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def ReleaseKey(hexKeyCode):

    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( hexKeyCode, 0x48, 0x0002, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))


def AltTab():
    '''
    Press Alt+Tab and hold Alt key for 2 seconds in order to see the overlay
    '''

    PressKey(0x012) #Alt
    PressKey(0x09) #Tab
    ReleaseKey(0x09) #~Tab

    time.sleep(2)       
    ReleaseKey(0x012) #~Alt


if __name__ =="__main__":

    AltTab()

The part I'm not understanding is related to signed and unsigned integers:

int has a range of -32768 - 32767

unsigned int has a range of 0 - 65535

I read: "The total range of numbers that can be displayed by a 2 byte number is 2^16, since you have 16 bits that can represent a number. 2^16 is the same as 65536, which since we count from 0, is the same as 0 - 65535. This obviously matches up with the values for an unsigned int, so you can see that this is how that type operates."

This seems to make sense, but there's one thing I don't understand:

1 byte = 8 bits 2 bytes = 16 bits

so why is a 2 byte number referred to as 2^16 rather than 2^8?


Solution

  • The part I'm not understanding is related to signed and unsigned integers:
    int has a range of -32768 - 32767
    unsigned int has a range of 0 - 65535

    FYI: the size of an int (and therefore the values it can hold) can actually be dependent on your environment. The sure fired way to know the size (bit width) of an integer variable type (at least as of C99) is to use one of the types defined in stdint.h, there you will find explicit types like int8_t and int16_t. Not typically required, but just a fun fact to one learning C.

    Anyway, on to your question. So "why is a 2 byte number referred to as 2^16 rather than 2^8"

    The 16 is for the number of bits. In 2 bytes there are 16 bits.

    The 2 is for the number of possibilities for each bit. (0 or 1)

    So 2 bytes can represent 2^16th numbers from 00000000000000002 to 11111111111111112