0

Trying to understand hexadecimal 0x notation in regards to memory locations and sizes in MiB (mebibytes) and KiB (kibibytes). Specifically, in a partition layout table I can see the following columns:

size        hex '0x' notation           
1 MiB       0x0010 0000    
12 MiB      0x00c0 0000
128 KiB     0x0002 0000

But I find it hard to translate/extract the logic to calculate and do the conversions for myself (for example convert from 24 MiB, 125 KiB, 16 MiB, to '0x' hex notation etc.).

Hence, I thought of writing a Python script (as you do) to do the conversions from MiB/KiB to 'Ox' and additions of '0x'. I found this [https://stackoverflow.com/a/8186974/6167676] but I failed to do anything meaningful from it.

To my surprise I could not find something online to help me do the conversions from MiB/KiB to the hex '0x' notation. In Python I found the hex function in an attempt to do basic additions between hex values in the hex '0x' notation:

def hex_add(h1, h2):
    return hex(int(h1, 0) + int(h2, 0))

How can use Python (built-in or not functions) to automatically calculate the conversion from MiB to the hex '0x' notation? Also, is the hex_add adequate to perform additions on '0x' notation?

Some code examples to demonstrate the conversion and addition in Python would be very useful.

1 Answers1

1

First, let's create some constants for KiB, MiB, GiB, etc. Don't worry about hex here, we just want the numbers in whatever form makes most sense to you—whether that's 1024 or 0x400 or 2**10 doesn't matter, since those are all the same number. So:

KiB = 1024
MiB = 1024 * KiB
GiB = 1024 * MiB
TiB = 1024 * GiB

Now, how much is 12MiB? Easy:

12 * MiB

Now, how much is 12MiB in hex?

hex(12 * MiB)

This gives you '0xc00000'.


As far as "adding in hex", that's not a thing you should do. Just add the numbers as numbers, then format the result in hex. For example, if you want to add 32KiB + 16KiB + 1MiB:

hex(32*KiB + 16*KiB + 1*MiB)

You wanted a bit more control over the output. If that's important, you'll need to use format strings (whether via the format function, the str.format method, or f-string literals) instead of hex.

You can specify a width to pad to, and a fill character to pad with. And you can use # to add the 0x automatically (in which case we have to pad to 8+2=10 characters instead of 8), or add the 0x manually (in which case we only have to pad to 8 characters, which makes a bit more sense):

format(12 * MiB, '#010x')
f"{12*MiB:#010x}"
f"0x{12*MiB:08x}"

You also wanted to separate the digits into blocks of 4. We can use a grouping character to get pretty close, but then we have to add an extra 1 to the width:

f"0x{12*MiB:09_x}"

… at which point we might as well use # again:

f"{12*MiB:#011_x}"

Now you've got '0x00c0_0000'. If you really need spaces between groups instead of underscores, then you'll need to get a bit ugly:

f"{12*MiB:#11_x}".replace('_', ' ')

(I believe there was a proposal to allow arbitrary grouping characters, but it was rejected, so the only options are _, ,, or n for "do whatever my locale says".)


So, if you want to print out your table:

print( "size        hex '0x' notation")
print(f"1 MiB       {12*MiB:#011_x}")
print(f"12 KiB      {12*KiB:#011_x}")
print(f"128 KiB     {128*KiB:#011_x}")

Or you can write a function. While we're at it, let's use an Enum instead of a bunch of separate constants:

import enum
class Prefixes(enum.Enum):
    Ki = 1024
    Mi = 1024 * Ki
    Gi = 1024 * Mi
    Ti = 1024 * Gi
def printrow(n, prefix):
    label = f"{n} {prefix.name}B"
    print(f"{label:<12}{n * prefix.value:#011_x}")
print("size        hex '0x' notation")
printrow(1, Prefixes.Mi)
printrow(12, Prefixes.Ki)
printrow(128, Prefixes.Ki)

This is obviously a lot more extensible, if you want to add more rows to the table.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • 2
    great answer! however, you say that `12 MiB = 0x0c0_0000` whereas on the question's table that equals to `0x00c00000`. Are these both the same? I understand that probably my question probably stems from my lack understanding hex in general .. –  Jul 17 '18 at 07:00
  • 1
    @Karim Oops, I forgot that the grouping character counts as part of the width. Edited the answer to fix that. But meanwhile, less, `0x0c0_0000` is the same value as `0x00c0_0000`. Leading zeros don't mean anything, just like in everyday arithmetic `0123` and `00123` are the same number. – abarnert Jul 17 '18 at 07:09