1

次のコードをどのように出力するのが最善でしょうか

#include <CoreFoundation/CoreFoundation.h> // Needed for CFSTR
int main(int argc, char *argv[])
{
    char *c_string = "Hello I am a C String. :-).";
    CFStringRef cf_string = CFStringCreateWithCString(0, c_string, kCFStringEncodingUTF8);

    // output cf_string
    //

}
4

1 に答える 1

9

ファイルにはバイトしか書き込めないため、任意のファイル (stdout または stderr を含む) に直接 CFString を書き込む API はありません。キャラクターは (やや) より理想的な概念です。ファイルに書き込むにはレベルが高すぎます。「これらのピクセルを書きたい」と言っているようなものです。最初にそれらを書き込む形式 (PNG など) を決定し、その形式でエンコードしてから、そのデータを書き込む必要があります。

キャラクターもそうです。それらを何らかの形式でバイトとしてエンコードしてから、それらのバイトを書き込む必要があります。

文字をバイト/データとしてエンコードする

まず、エンコーディングを選択する必要があります。ターミナルで表示するには、おそらく UTF-8 が必要ですkCFStringEncodingUTF8。ファイルへの書き込みには…通常はUTF-8が必要です。実際、他に何か特別なことが必要でない限り、ほとんどの場合 UTF-8 が必要です。

次に、文字をバイトとしてエンコードする必要があります。C 文字列を作成するのも 1 つの方法です。もう 1 つは、CFData オブジェクトを作成することです。さらに別の方法として、バイト (null で終了していない) を直接抽出する方法があります。

あなたは CF に固執したいとおっしゃいましたので、C の文字列オプションはスキップします (どのような呼び出しwriteでも を呼び出さなければならないため、とにかく効率が悪くなります)。これはstrlen簡単ですが、特に大きな文字列で使用する場合は遅くなります。および/または頻繁に。代わりに、CFData を作成します。

さいわい、CFString には、CFString の内容から CFData オブジェクトを作成するための API が用意されています。残念ながら、これは外部表現を作成する場合にのみ機能します。これを stdout に書きたくないでしょう。通常のファイルの内容全体として書き出す場合にのみ適しています。

そのため、レベルを下げて自分でバイトを取得する必要があります。この関数は、バッファ (メモリの領域) とそのバッファのサイズ (バイト単位) を取ります。

CFStringGetLengthバッファのサイズには使用しないでください。バイトではなく文字をカウントし、文字数とバイト数の関係は常に線形ではありません。(たとえば、一部の文字は 1 バイトで UTF-8 にエンコードできますが、すべてではありません。ほぼすべてではありません。その他の文字については、必要なバイト数が異なります。)

正しい方法は 2 回呼び出すことですCFStringGetBytes : 1 回はバッファ ( NULL) なしで、(与えられていないバッファに書き込もうとせずに) 与えられるバイト数を単純に教えてくれます。次に、そのサイズのバッファーを作成し、そのバッファーで再度呼び出します。

を使用してバッファを作成することもできmallocますが、CF のものに固執したいので、代わりにこの方法で行います:容量が最初の呼び出しから取得したバイト数である CFMutableData オブジェクトを作成し、その長さを同じまで増やします。バイト数、データの変更可能なバイト ポインターを取得します。そのポインターは、書き込む必要があるバッファーへのポインターです。への 2 番目の呼び出しに渡すポインターです。CFStringGetBytesCFStringGetBytes

これまでの手順を要約すると、次のようになります。

  • CFStringGetBytes必要なバッファーの大きさを調べるには、バッファーなしで呼び出します。
  • その容量の CFMutableData オブジェクトを作成し、その長さをそのサイズまで増やします。
  • バッファーである CFMutableData オブジェクトの変更可能なバイト ポインターを取得し、今度はCFStringGetBytesバッファーを使用して再度呼び出し、データ オブジェクト内の文字をバイトにエンコードします。

それを書き出す

純粋な CF でバイト/データをファイルに書き込むには、CFWriteStreamを使用する必要があります。

残念ながら、 のような優れた Cocoa API に相当する CF はありません[NSFileHandle fileHandleWithStandardOutput]。stdout への書き込みストリームを作成する唯一の方法は、URL でラップされた stdout へのパスを使用して作成することです。

パスから簡単に URL を作成できます。標準出力デバイスへのパスは/dev/stdoutであるため、作成する URL は次のようになります。

CFURLRef stdoutURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/dev/stdout"), kCFURLPOSIXPathStyle, /*isDirectory*/ false);

(もちろん、作成したすべてのものと同様に、リリースする必要があります。)

URL があれば、そのように参照されたファイルの書き込みストリームを作成できます。次に、ストリームを開き、そこにデータを書き込めるようにし(データのバイト ポインタその長さを取得する必要があります)、最後にストリームを閉じます

書き込んでいるものが改行で終わっていない場合、テキストが欠落している/表示されていない可能性があることに注意してください。NSLogあなたに代わって stderr に書き込むときに改行を追加します。自分で stderr に書き込む場合は、それを行う必要があります (または結果を受け入れる必要があります)。

そう:

于 2013-09-10T19:13:13.233 に答える