§ Readable pointers

I recently had to debug a whole bunch of code that manipuates pointers, so I need to stare at random things like 0x7f7d6ab2c0c0, like so:
mkClosure_capture0_args0 (0x7f079ae2a0c0:) -> 0x556b95a23350:
mkClosure_capture0_args0 (0x7f079ae2a0e0:) -> 0x556b95a3f3e0:
mkClosure_capture0_args2 (0x7f079ae2a000:, 
  0x556b95a23350:, 0x556b95a3f3e0:) -> 0x556b95a232e0:
evalClosure (0x556b95a232e0:)
  ⋮evalClosure (0x556b95a23350:)
  ⋮  ⋮mkConstructor1 (MkSimpleInt, 0x1) -> 0x556b9596c0b0:
  ⋮=>0x556b9596c0b0:
  ⋮isConstructorTagEq (0x556b9596c0b0:MkSimpleInt, MkSimpleInt) -> 1
  ⋮extractConstructorArg  0 -> 0x1:
  ⋮evalClosure (0x556b95a3f3e0:)
  ⋮  ⋮mkConstructor1 (MkSimpleInt, 0x2) -> 0x556b95a23190:
  ⋮=>0x556b95a23190:
  ⋮isConstructorTagEq (0x556b95a23190:MkSimpleInt, MkSimpleInt) -> 1
  ⋮extractConstructorArg  0 -> 0x2:
  ⋮mkConstructor1 (MkSimpleInt, 0x3) -> 0x556b95902a30:
=>0x556b95902a30:
I got annoyed because it's hard to spot differences across numbers. So I wrote a small '''algorithm''' that converts this into something pronounceable:
char *getPronouncableNum(size_t N) {
     const char *cs = "bcdfghjklmnpqrstvwxzy";
     const char *vs = "aeiou";

     size_t ncs = strlen(cs); size_t nvs = strlen(vs);

     char buf[1024]; char *out = buf;
     int i = 0;
     while(N > 0) {
         const size_t icur = N % (ncs * nvs);
         *out++ = cs[icur%ncs]; *out++ = vs[(icur/ncs) % nvs];
         N /= ncs*nvs;
         if (N > 0 && !(++i % 2)) { *out++ = '-'; }
     }
     *out = 0;
     return strdup(buf);
};
which gives me the much more pleasant output:
mkClosure_capture0_args0 (0x7fbf49b6d0c0:cisi-jece-xecu-yu) 
  -> 0x561c5f11f9d0:suje-zoni-ciho-ko
mkClosure_capture0_args0 (0x7fbf49b6d0e0:qosi-jece-xecu-yu) 
  -> 0x561c5f12f1b0:leda-guni-ciho-ko
mkClosure_capture0_args2 (0x7fbf49b6d000:ziqi-jece-xecu-yu, 
  0x561c5f11f9d0:suje-zoni-ciho-ko, 
  0x561c5f12f1b0:leda-guni-ciho-ko) 
    -> 0x561c5f11f960:kuhe-zoni-ciho-ko
evalClosure (0x561c5f11f960:kuhe-zoni-ciho-ko)
  ⋮evalClosure (0x561c5f11f9d0:suje-zoni-ciho-ko)
  ⋮  ⋮mkConstructor1 (MkSimpleInt, 0x1) -> 0x561c5f129c10:qifa-duni-ciho-ko
  ⋮=>0x561c5f129c10:qifa-duni-ciho-ko
  ⋮isConstructorTagEq (0x561c5f129c10:MkSimpleInt, MkSimpleInt) -> 1
  ⋮extractConstructorArg  0 -> 0x1:ca
  ⋮evalClosure (0x561c5f12f1b0:leda-guni-ciho-ko)
  ⋮  ⋮mkConstructor1 (MkSimpleInt, 0x2) -> 0x561c5f120200:nuhi-zoni-ciho-ko
  ⋮=>0x561c5f120200:nuhi-zoni-ciho-ko
  ⋮isConstructorTagEq (0x561c5f120200:MkSimpleInt, MkSimpleInt) -> 1
  ⋮extractConstructorArg  0 -> 0x2:da
  ⋮mkConstructor1 (MkSimpleInt, 0x3) -> 0x561c5f100010:kuqi-koni-ciho-ko
=>0x561c5f100010:kuqi-koni-ciho-ko
The strings of the form ziqi-jece-xecu-yu makes it way easier to see control flow. I can also see if two pointers are close, based on shared suffixes: ciho-ko is shared, which means the numbers are themselves close.
  • It turns out there's a system called proquintsthat allows for such a thing already!