0
votes

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?

3
because it has 16 bits. each bit can hold 2 values, thus 2^16 possible numbers with 2 bytes - pippin1289
Ah of course, thank you. - Phoenix
Note: Per C, a byte is at least 8 bits. - chux - Reinstate Monica
Are you using ancient DOS compilers? Or are you compiling for some embeded systems? Modern CPU architectures have 32-bit int and can represent 2^32 different values, the range is 0 to 2^32-1 for unsigned and -2^31 to 2^31-1 for signed int - phuclv

3 Answers

1
votes

A 2 byte number has 16 bits (2 x 8 bits). The function that tells you the highest unsigned number that can be represented by a given number of bits is 2^n-1, so for instance 8 bits can represents numbers 0 to 255, 16 bits 0 to 65,535, etc.

The reason for this is simple. Consider the first number that cannot be represented by (say) 16 bits. That would be 1 with 16 zeros, as that's the smallest binary number with 17 digits. That's 2^16. So the largest number that can be represented that way is 2^16-1.

Also note that the size of int in C will depend on your C compiler. It may not always be 2 bytes long.

1
votes

2-byte number contains 16 bits. Each of them can hold 2 values, thus it can generate 2^16 possible numbers and this is the number of different information you can encode by it.

1
votes

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