Search code examples
ccharprintfunsigned-char

C printf unsigned char array


I have an unsigned char array unsigned char* name = malloc(nameLength); - how can I print it with printf? %sdoes not seem to work correctly, neither does %u (seeing random icons).

Here's how I create the data I want to print:

__int32 nameLength;
ReadProcessMemory(hProcess, (LPCVOID)(classNamePtr + 0x0004), &nameLength, sizeof(__int32), 0); //Reads nameLength to be 13 in this case
unsigned char* name = malloc(nameLength+5); //Add 5 for good measure, it is null terminated
ReadProcessMemory(hProcess, (LPCVOID)(nameStrPtr), name, nameLength, 0);
name[nameLength] = 0; //null terminate

printf("%s", name); //Outputs single character strange characters, like an up icon

Solution

  • When one detects a non-printable char, output an escape sequence or hexadecimal value

    #include <ctype.h>
    #include <string.h>
    #include <stdio.h>
    
    int printf_ByteArray(const unsigned char *data, size_t len) {
      size_t i;
      int result = 0;
      for (i = 0; i < len; i++) {
        int y;
        int ch = data[i];
        static const char escapec[] = "\a\b\t\n\v\f\n\'\"\?\\";
        char *p = strchr(escapec, ch);
        if (p && ch) {
          static const char escapev[] = "abtnvfn\'\"\?\\";
          y = printf("\\%c", escapev[p - escapec]);
        } else if (isprint(ch)) {
          y = printf("%c", ch);
        } else {
          // If at end of array, assume _next_ potential character is a '0'.
          int nch = i >= (len - 1) ? '0' : data[i + 1];
          if (ch < 8 && (nch < '0' || nch > '7')) {
            y = printf("\\%o", ch);
          } else if (!isxdigit(nch)) {
            y = printf("\\x%X", ch);
          } else {
            y = printf("\\o%03o", ch);
          }
        }
        if (y == EOF)
          return EOF;
        result += y;
      }
      return result;
    }
    

    If data contained one of each byte, sample follows:

    \0...\6\a\b\t\n\v\f\xD\xE\xF\x10...\x1F !\"#$%&\'()*+,-./0123456789:;<=>\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F...\xFE\o377

    The selection of escape sequences will vary with code goals. The set above attempts to conform to something a C parser would accept.
    Note: With the last else, always outputting a 3-digit octal sequence has scanning advantages, but folks are more accustomed to hexadecimal than octal.
    Adjusted to conditionally print in hex depending on the following character.