转义printf()中的所有特殊字符

时间:2014-03-03 15:40:51

标签: c++ c char escaping printf

是否有一种简单的方法可以转义printf()函数中的所有特殊字符?

我想知道如何做到这一点的原因是因为我打印了许多字符,其中可能包含特殊字符,例如空字符(\0)和哔声字符,我只是想看到字符串的内容。

目前我使用以下代码

适用于空字符。逃脱所有特殊角色的最简单方法是什么?

int length;
char* data = GetData( length ); // Fills the length as reference

for( int i = 0;  i < length;  i++ )
{
    char c = data[ i ];
    printf( "%c", ( c == 0  ?  '\\0'  :  data[ i ] ) );
}

4 个答案:

答案 0 :(得分:3)

首先,'\\0'是一个双字符的字面值,它应该是一个双字符字符串。至于将所有特殊字符打印为转义码,您需要更多代码:

switch (data[i])
{
case '\0':
    printf("\\0");
    break;
case '\n':
    printf("\\n");
    break;

/* Etc. */

default:
    /* Now comes the "hard" part, because not all characters here
     * are actually printable
     */
    if (isprint(data[i]))
        printf("%c", data[i]);  /* Printable character, print it as usual */
    else
        printf("\\x%02x", data[i]); /* Non-printable character, print as hex value */

    break;
}

答案 1 :(得分:2)

使用isprint库函数确定字符是否可打印:

#include <ctype.h>
...
if (isprint(data[i]))
  printf(" %c", data[i]);    // prints character
else
  printf(" %d", data[i]);    // prints code value for character

答案 2 :(得分:0)

如果代码需要用 no 歧义编写,请使用C语法:

#include <ctype.h>
#include <string.h>
#include <stdio.h>

void EscapePrint(int ch) {
  // Delete or adjust these 2 arrays per code's goals
  // All simple-escape-sequence C11 6.4.4.4
  static const char *escapev = "\a\b\t\n\v\f\r\"\'\?\\";
  static const char *escapec = "abtnvfr\"\'\?\\";
  char *p = strchr(escapev, ch);
  if (p && *p) {
    printf("\\%c", escapec[p - escapev]);
  } else if (isprint(ch)) {
    fputc(ch, stdout);
  } else {
    // Use octal as hex is problematic reading back
    printf("\\%03o", ch);
  }
}

void EscapePrints(const char *data, int length) {
  while (length-- > 0) {
    EscapePrint((unsigned char) *data++);
  }
}

或者,代码可以

void EscapePrint(char sch) {
  int ch = (unsigned char) sch;
  ...
}
void EscapePrints(const char *data, int length) {
  while (length-- > 0) {
    EscapePrint(*data++);
  }
}

要使用十六进制转义序列或缩短八进制转义序列,代码需要确保 next 字符不会产生歧义。上述代码中不会出现这种复杂情况,因为它使用3位八进制转义序列。修改后的代码类似于:

  } else {
    if ((ch == 0) && (nextch < '0' || nextch > '7')) {
      fputs("\\0", stdout);
    }
    else if (!isxdigit((unsigned char) nextch)) {
      printf("\\x%X", ch);
    }
    else {
      // Use octal as hex is problematic reading back
      printf("\\%03o", ch);
    }
  }

答案 3 :(得分:0)

#include <stdio.h>
#include <ctype.h>


/* Converts a buffer of specified lenth to
 * ASCII representation as it was a C string literal.
 * Returns how much bytes from source was processed
 * (ideally ret == src_sz)
 */
int binbuf_to_escaped_C_literal(const char *src_buf, size_t src_sz, char *dst_str, size_t dst_sz)
{
    const char *src = src_buf;
    char *dst = dst_str;

    while (src < src_buf + src_sz)
    {
        if (*src == '\\')
        {
            *dst++ = '\\';
            *dst++ = *src++;
        }
        else if (isprint(*src))
        {
            *dst++ = *src++;
        }
        else
        {
            switch(*src)
            {
                case '\n':
                    *dst++ = '\\';
                    *dst++ = 'n';
                    break;
                case '\r':
                    *dst++ = '\\';
                    *dst++ = 'r';
                    break;
                case '\t':
                    *dst++ = '\\';
                    *dst++ = 't';
                    break;
                case '\0':
                    *dst++ = '\\';
                    *dst++ = '0';
                    break;
                default:
                    sprintf(dst, "0x%x", *src);
                    dst += 4;
            }
            src++;
        }

        // next iteration requires up to 5 chars in dst buffer, for ex.  "0xab\0"
        if (dst > (dst_str + dst_sz - 5)) {
            break;
        }
    }

    *dst = '\0';

    return src - src_buf;
}


int main(int argc, char **argv)
{
    const char binbuf[] = "strange \n\r\t\0\0\0\0\0\\\\ string";
    size_t sz = sizeof(binbuf) - 1; // drop trailing nul terminator

    char escaped[128];

    if (binbuf_to_escaped_C_literal(binbuf, sz, escaped, sizeof(escaped)) != sz) {
        fprintf(stderr, "Destination string buffer is too small\n");
        return 1;
    }

    printf("Escaped: %s\n", escaped);

    // $ ./escape-binary-buf                                          //
    // Escaped: strange \n\r\t\0\0\0\0\0\\\\ string                   //

    return 0;
}