Search code examples
gobitwise-operators

Bitwise not to how to do without ffffffff


When doing bitwise not, get a lot ffffffff. How to do correctly?

    space := "    "
    str := "12345678999298765432179.170.184.81"

    sp := len(str) % 4
    if sp > 0 {
        str = str + space[0:4-sp]
    }
    fmt.Println(str, len(str))

    hx := hex.EncodeToString([]byte(str))
    ln := len(hx)
    a, _ := strconv.ParseUint(hx[0:8], 16, 0)
    for i := 8; i < ln; i += 8 {
        b, _ := strconv.ParseUint(hx[i:i+8], 16, 0)
        a = a ^ b
    }

    xh := strconv.FormatUint(^a, 16)
    fmt.Println(xh)

output ffffffffc7c7dbcb

I need only c7c7dbcb


Solution

  • You get a lot of leading ff because your a number in fact is only 32-bit "large" but is used "within" a 64-bit uint64 value. (You're processing numbers with 8 hex digits = 4 bytes data = 32 bit.) It has 4 leading 0 bytes, which when negated will turn into ff. You can verify this with:

    fmt.Printf("a %#x\n",a)
    

    Outputs:

    a 0x38382434
    

    To get rid of those leading ff, convert the result to uint32:

    xh := strconv.FormatUint(uint64(uint32(^a)), 16)
    fmt.Println(xh)
    

    (Converting back to uint64 is because strconv.FormatUint() expects / requires uint64.)

    This outputs:

    c7c7dbcb
    

    Another option is to apply a 0xffffffff bitmask:

    xh = strconv.FormatUint(^a&0xffffffff, 16)
    fmt.Println(xh)
    

    Also note that you could print it using fmt.Printf() (or fmt.Sprintf() if you need it as a string) where you specify %08x verb which also adds leading zeros should the input has more than 3 leading 0 bits (and thus strconv.FormatUint() would not add leading hex zeros):

    fmt.Printf("%08x", uint32(^a))
    

    This outputs the same. Try the examples on the Go Playground.