Maximum and minimum value of C types integers from Python

According to: [Python 3 docs]: Numeric Types – int, float, complex:

Integers have unlimited precision.

Translated to code:

>>> i = 10 ** 100
>>> i
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> len(str(i))
101
>>> i.bit_length()
333

On the other hand, each C type has a fixed size (depending on platform / architecture), as clearly shown in [CPPReference]: Fundamental types.

Since [Python 3 docs]: ctypes – A foreign function library for Python doesn’t mention anything about types limits (note that there is some stuff not documented there), let’s find them out manually.

code00.py:

#!/usr/bin/env python3

import sys
from ctypes import c_int8, c_uint8, c_byte, c_ubyte, c_int16, c_uint16, \
    c_int32, c_uint32, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, \
    c_int64, c_uint64, \
    sizeof


def limits(c_int_type):
    signed = c_int_type(-1).value < c_int_type(0).value
    bit_size = sizeof(c_int_type) * 8
    signed_limit = 2 ** (bit_size - 1)
    return (-signed_limit, signed_limit - 1) if signed else (0, 2 * signed_limit - 1)


def main(*argv):
    test_types = (
        c_int8,
        c_uint8,
        c_byte,
        c_ubyte,
        c_int16,
        c_uint16,
        c_int32,
        c_uint32,
        c_int,
        c_uint,
        c_long,
        c_ulong,
        c_longlong,
        c_ulonglong,
        c_int64,
        c_uint64,
    )
    for test_type in test_types:
        print("{:s} limits: ({:d}, {:d})".format(test_type.__name__, *limits(test_type)))


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

Notes:

  • Code relies on the fact that for a certain integral type, its interval (and limits are interval’s endpoints) is:

    • signed (2‘s complement): [-(2 bit_size – 1), 2 bit_size – 1 – 1]

    • unsigned: [0, 2 bit_size – 1]

  • To check the a type’s signum, use -1 (which will automatically be converted to the upper limit (due to wrap around arithmetic) by unsigned types)

  • There are lots of duplicates the output (below), because some types are simply “aliases” to others

  • The rest of your task (creating a function that compares a Python int to the CTypes type limits, and raises an exception if it isn’t) is trivial, so I didn’t implement it

  • This is for demonstrating purpose only, so I didn’t do any argument check

Output:

  • Win:

    • Python pc064 (064bit):

      [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q052475749]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ./code00.py
      Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
      
      c_byte limits: (-128, 127)
      c_ubyte limits: (0, 255)
      c_byte limits: (-128, 127)
      c_ubyte limits: (0, 255)
      c_short limits: (-32768, 32767)
      c_ushort limits: (0, 65535)
      c_long limits: (-2147483648, 2147483647)
      c_ulong limits: (0, 4294967295)
      c_long limits: (-2147483648, 2147483647)
      c_ulong limits: (0, 4294967295)
      c_long limits: (-2147483648, 2147483647)
      c_ulong limits: (0, 4294967295)
      c_longlong limits: (-9223372036854775808, 9223372036854775807)
      c_ulonglong limits: (0, 18446744073709551615)
      c_longlong limits: (-9223372036854775808, 9223372036854775807)
      c_ulonglong limits: (0, 18446744073709551615)
      
      Done.
      
    • Python pc032 (032bit):

      [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q052475749]> "e:\Work\Dev\VEnvs\py_pc032_03.10_test0\Scripts\python.exe" ./code00.py
      Python 3.10.1 (tags/v3.10.1:2cd268a, Dec  6 2021, 18:54:59) [MSC v.1929 32 bit (Intel)] 032bit on win32
      
      c_byte limits: (-128, 127)
      c_ubyte limits: (0, 255)
      c_byte limits: (-128, 127)
      c_ubyte limits: (0, 255)
      c_short limits: (-32768, 32767)
      c_ushort limits: (0, 65535)
      c_long limits: (-2147483648, 2147483647)
      c_ulong limits: (0, 4294967295)
      c_long limits: (-2147483648, 2147483647)
      c_ulong limits: (0, 4294967295)
      c_long limits: (-2147483648, 2147483647)
      c_ulong limits: (0, 4294967295)
      c_longlong limits: (-9223372036854775808, 9223372036854775807)
      c_ulonglong limits: (0, 18446744073709551615)
      c_longlong limits: (-9223372036854775808, 9223372036854775807)
      c_ulonglong limits: (0, 18446744073709551615)
      
      Done.
      
  • Nix (LinuxWSL2) – Python pc064:

    (qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q052475749]> python ./code00.py
    Python 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0] 064bit on linux
    
    c_byte limits: (-128, 127)
    c_ubyte limits: (0, 255)
    c_byte limits: (-128, 127)
    c_ubyte limits: (0, 255)
    c_short limits: (-32768, 32767)
    c_ushort limits: (0, 65535)
    c_int limits: (-2147483648, 2147483647)
    c_uint limits: (0, 4294967295)
    c_int limits: (-2147483648, 2147483647)
    c_uint limits: (0, 4294967295)
    c_long limits: (-9223372036854775808, 9223372036854775807)
    c_ulong limits: (0, 18446744073709551615)
    c_long limits: (-9223372036854775808, 9223372036854775807)
    c_ulong limits: (0, 18446744073709551615)
    c_long limits: (-9223372036854775808, 9223372036854775807)
    c_ulong limits: (0, 18446744073709551615)
    
    Done.
    

Note (more or less related): Many people encounter problems when calling functions via CTypes. Mentioning [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati’s answer) just in case.

Leave a Comment