C新手,ascii控制功能

时间:2011-01-11 00:48:20

标签: c

我编写了一个在C语言中运行良好的程序,它将不可读的ASCII转换为它们的字符值。如果是C大师,我会很感激吗?会告诉我一个更好的方法,我目前已经做了,主要是这一部分:

if (isascii(ch)) {
    switch (ch) {
        case 0:
            printControl("NUL");
            break;
        case 1:
            printControl("SOH");
            break;

        .. etc (32 in total)

        case default:
            putchar(ch);
            break;
    }
}

做一个大的开关是正常的吗?或者我应该使用其他方法(从ascii表输入?)

4 个答案:

答案 0 :(得分:3)

如果你总是做同样的操作(例如putchar),你可以静态初始化一个映射到每个角色应该映射的数组。然后,您可以通过根据传入字符的偏移量巧妙地访问数组来访问正确的映射值。

例如,(在伪代码中 - 自从我用C编写以来已经有一段时间了),你可以定义:

const char* [] map = {"NUL", "SOH, ...};

然后通过以下方式巧妙地索引:

const char* val = map[((int)ch)];

获得你的价值。

如果“from”值不是连续的,您将无法使用此功能;在这种情况下,您需要有一些条件块。但是,如果你可以利用顺序性,你应该。

答案 1 :(得分:1)

很多年前,当8位微处理器的汇编语言是我花费时间的时候,我会写一些类似的东西

printf("%3.3s", 
       ("NULSOHSTXETXEOTENQACKBELBS HT LF VT FF CR SO SI "
        "DLEDC1DC2DC3DC4NAKSYNETBCANEM SUBESCFS GS RS US ")[3*ch]);

但不是因为它特别好。而乘以三是令人讨厌的,因为8位微处理器不会成倍增加,因此需要移位和加法,以及备用寄存器。

更像C的结果将是使用每个控件有四个字节的表,其中包含NUL字节。这允许每个条目被称为字符串常量,但是为32个指针节省了额外的存储空间。

const char *charname(int ch) {
    if (ch >= 0 && ch <= 0x20)
        return ("NUL\0"  "SOH\0"  "STX\0"  "ETX\0"  /* 00..03 */
                "EOT\0"  "ENQ\0"  "ACK\0"  "BEL\0"  /* 04..07 */
                "BS\0\0" "HT\0\0" "LF\0\0" "VT\0\0" /* 08..0B */
                "FF\0\0" "CR\0\0" "SO\0\0" "SI\0\0" /* 0C..0F */
                "DLE\0"  "DC1\0"  "DC2\0"  "DC3\0"  /* 10..13 */
                "DC4\0"  "NAK\0"  "SYN\0"  "ETB\0"  /* 14..17 */
                "CAN\0"  "EM\0\0" "SUB\0"  "ESC\0"  /* 18..1B */
                "FS\0\0" "GS\0\0" "RS\0\0" "US\0\0" /* 1C..1F */
                "SP\0\0") + (ch<<2);                /* 20 */
    if (ch == 0x7f)
        return "DEL";
    if (ch == EOF)
        return "EOF";
    return NULL;
}

我尝试格式化主表,因此其组织清晰。对于自己命名的字符,该函数返回NULL,或者不是7位ASCII。否则,它返回一个指向NUL终止的ASCII字符串的指针,该字符串包含该控制字符的常规缩写,或者在文件末尾由C标准IO例程返回的非字符EOF的“EOF”。

请注意将每个字符名称插槽填充到恰好四个字节所需的工作量。在这种情况下,使用脚本语言或单独的程序构建此表将是一个好主意。在这种情况下,简单的答案是构建一个129条目表(或257条目),其中包含所有7位ASCII(或首选代码页中扩展为8位)字符的名称,并为{{添加一个额外的插槽1}}。

请参阅EOF中声明的函数的来源,以获取处理<ctype.h>的额外空间的示例。

答案 2 :(得分:0)

你可以做一个这么大的转换,但它确实有点难以管理。

我接近这个的方法是为每个项目构建一个char c; char* ctrl;的数组。然后你可以循环遍历数组。这样可以更容易地维护数据。

请注意,如果您使用特定范围内的每个字符(例如,字符0到32),那么您的数组只需要名称,而不需要存储字符值。

答案 3 :(得分:0)

我想说用vals(0-32)和它们相应的控制字符串(“NUL”,“SOH”)构建一个表。 (在这种情况下,表只需要一个数组)

然后你可以检查它是否在范围内是表的索引,以便将字符串传递给printControl()函数。