2011-01-11 6 views
2

私は、読みにくいASCIIを文字値に変換するC言語でうまく動作するプログラムを書いています。 Cマスターなら分かりますか?私が現在やっているより良いやり方を教えてくれるでしょう、主にこのセクション: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; 
    } 
} 

スイッチを大きくするのは普通ですか?または私は(アスキーテーブルからの入力?)他のいくつかの方法を使用する必要があり

+3

私はCマスターではありませんが、スイッチの最初の部分を文字列の配列に置き換えることができます。 – svens

+0

文字列は配列であり、ポインタではありません。したがって、以下のsvensのアドバイスは2d配列を必要とします。これは特に、すべての文字列が同じ(またはほぼ同じ)長さを持つこのような場合に最適な実装です。 –

答えて

1

あまりに何年も前、私は

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

のようなものではなく、その特に優れているために書かれているだろう。また、8ビットのマイクロは乗算されないので、シフトと加算の両方を必要とし、スペアレジスタも必要になるため、3倍の乗算は面倒です。

C言語のような結果は、NULバイトを含むコントロールごとに4バイトのテーブルを使用することです。これにより、各エントリを文字列定数と呼ぶことができますが、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; 
} 

メインテーブルを整理してその組織が明確になるようにしました。この関数は、自分自身の名前を持つ文字、または7ビットASCIIでない文字の場合はNULLを返します。それ以外の場合は、その制御文字の従来の省略形を含むNUL終端のASCII文字列へのポインタ、またはファイルの最後にC標準のIOルーチンによって返された非文字の "EOF" EOFを返します。

各文字名のスロットを正確に4バイトにする努力に注意してください。これは、スクリプト言語や別のプログラムでこのテーブルを構築することは良い考えです。その場合、単純な答えは、EOFの余分なスロットを持つすべての7ビットASCII(または8ビットの拡張コードページ)文字を含む129エントリテーブル(または257エントリ)を構築することです。

EOFの余分なスペースを処理するサンプルについては、<ctype.h>で宣言されている関数のソースを参照してください。

0

をあなたは、これは大きなスイッチを作ることができますが、それは管理が少し困難になるん。

私はこれに近づくような方法は、各項目のchar c; char* ctrl;を持つ配列を構築することです。その後、配列をループすることができます。これにより、データを維持することが少し容易になります。あなたが特定の範囲内のすべての文字を使用する場合(例えば、〜32文字0)、その後、あなたの配列は名前だけを必要とし、文字値を格納するのに必要ではないだろうと

注意。

3

あなたが常に同じ操作(例えば、putcharマクロを)やっている場合は、あなただけの静的に各文字がマップするべきかにマップ配列を初期化することができます。次に、着信文字のオフセットごとに配列にスマートにアクセスすることによって、適切なマッピング値にアクセスできます。例えば

、(擬似コードで - 私はCで書いたので、それがしばらくされていますが)、あなたが定義します

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

、その後、スマートのようなものを経由してインデックス:

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

あなたの価値を得る。

「差出人」の値が連続していない場合は、これを使用できません。その場合、いくつかの条件付きブロックが必要になります。しかし、あなたが順性を活用できるなら、あなたはすべきです。

+1

多分それはかもしれません:const char * const map [] ...文字列への定数ポインタの定数配列を効果的に作成します。 – Schultz9999

+0

Schultz9999が正しいです、それは改善になるでしょう。 – kvista

+0

連続していない場合でも、制御文字列にマップする定数テーブルを作成できます。そうすれば、条件付きブロックを削除し、代わりにメモリ検索に頼ることになります。 –

0

私はヴァルス(0-32)およびその対応する制御文字列(「NUL」、「SOH」)を使用してテーブルを構築すると言うでしょう。それはあなたのPRINTCONTROL()関数に渡す文字列を取得するには、テーブルへのインデックスが範囲内にある場合

は、次に、あなただけ確認することができます(この場合、テーブルには、単にアレイが必要です)。 8ビットのミクロスためのアセンブリ言語は、私は私の時間を費やしたかだったとき

関連する問題