2012-01-16 6 views
7

は、C++標準ライブラリではstrncpyに相当正確なありますか?私は終わりの0に達するまで、あるバッファから別のバッファに文字列をコピーする関数を意味しますか?たとえば、TCPパケットなどの安全でないソースから文字列を解析する必要がある場合、データを処理しながら長さのチェックを実行できます。std :: stringと同じstrncpyですか?

私はすでにこのトピックに関してたくさんの検索を行いましたが、興味深いトピックもいくつか見つかりましたが、これらの人々はすべてstd :: string :: assignに満足していました。パラメータ。この機能を持つ私の問題は、終端のnullはすでにヒットしている場合、それは任意のチェックを実行しないこと、である - それは、文字列のバッファにそれを行うだろうちょうどmemcpyののようなデータを深刻与えられた大きさを取り、コピー。このようにして、対処しながらそのようなチェックがあった場合、実行しなければならなかったよりもはるかに多くのメモリが割り当てられ、コピーされます。私は現在、この問題を回避働いている方法だが、私は避けたいと思い、いくつかのオーバーヘッドがある 

// Get RVA of export name 
    const ExportDirectory_t *pED = (const ExportDirectory_t*)rva2ptr(exportRVA); 
    sSRA nameSra = rva2sra(pED->Name); 

    // Copy it into my buffer 
    char *szExportName = new char[nameSra.numBytesToSectionsEnd]; 
    strncpy(szExportName, 
      nameSra.pSection->pRawData->constPtr<char>(nameSra.offset), 
      nameSra.numBytesToSectionsEnd); 
    szExportName[nameSra.numBytesToSectionsEnd - 1] = 0; 

    m_exportName = szExportName; 
    delete [] szExportName; 

コードのこの作品は、PE-バイナリのための私のパーサの一部(あります正確には、エクスポートテーブルを解析するルーチンの名前です)。 rva2sraは、相対仮想アドレスをPEセクション相対アドレスに変換します。 ExportDirectory_t構造は、ゼロで終了する文字列でなければなりませんバイナリのエクスポート名にRVAが含まれています。 (誰かがそれを希望の場合、最終的にクラッシュするセクションに属していない私のプログラムがメモリに実行するだろう終了するゼロを省略することができるだろう - しかし、それは必ずしもそうである必要はありません。最良の場合...)。

自分でこのような機能を実現するための大きな問題ではないだろうが、C++標準ライブラリに実装され、このための解決策があった場合、私はそれを好みます。

+7

'std :: string'sはNULLで終了しません。文字列のコピー、または最初のヌルバイトまでのすべてのコピーを必要としますか(それは存在する場合としない場合があります)? –

+0

ああ、知っておいてよかった。私は最初のnullバイトまですべてをコピーしたいと思います。 – athre0z

+1

[頼むように気をつけてください](http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html) –

答えて

11

あなたは外のstringを作りたいバッファはその中に少なくとも一つのNULはその後、あなただけのコンストラクタに渡すことができたことがわかっている場合:あなたがいない場合

const char[] buffer = "hello\0there"; 

std::string s(buffer); 

// s contains "hello" 

確認し、あなただけの最初のヌルの文字列を検索する必要があり、その多くのデータのコピーを作成するstringのコンストラクタを教えて:

int len_of_buffer = something; 
const char* buffer = somethingelse; 

const char* copyupto = std::find(buffer, buffer + len_of_buffer, 0); // find the first NUL 

std::string s(buffer, copyupto); 

// s now contains all the characters up to the first NUL from buffer, or if there 
// was no NUL, it contains the entire contents of buffer 

あなたはWすることができますあなたは単一引数のコンストラクタを渡した場合

std::string string_ncopy(const char* buffer, std::size_t buffer_size) { 
    const char* copyupto = std::find(buffer, buffer + buffer_size, 0); 

    return std::string(buffer, copyupto); 
} 

しかし、注意すべき一つのこと:整頓小さな関数にアップ(NULがバッファ内に存在しない場合でも、常に動作します)は、第2のバージョンをラップconst char*それ自体では、NULを見つけるまで実行されます。 std::stringという単一引数のコンストラクタを使用する場合は、バッファに少なくとも1つのNULがあることが重要です。

std::stringの場合、strncpyと完全に等価ではありません。

+0

ありがとう、それは私が探していたものです。 – athre0z

1

は、クラスのコンストラクタを使用します。

string::string str1("Hello world!"); 
string::string str2(str1); 

これは、このマニュアルに従って、正確なコピーが得られます:http://www.cplusplus.com/reference/string/string/string/

+3

OPは探していません'strcpy'ではなく' strncpy'です。 – pmr

+0

@pmr:OPは彼が最初のNULLバイトまでしか望んでいないことを明確にしました。 –

+0

はい、それも当てはまります。 –

1

std::stringを使用することができ、次のシグネチャを持つコンストラクタを持っています

string (const char * s, size_t n); 

次の説明付き:

コンテンツはSで指された文字の配列の最初のn文字によって形成された文字列のコピーに初期化されます。

+0

これはヌルバイトで終わらないことに注意してください( "C文字列"ではなく "文字の配列"と言います)。それはあなたが望むものかもしれません。 –

+2

あなたの返事をありがとうございますが、それは私が知りたかったものではありません。コンストラクタは、最初のヌルバイトに達するまで、またはサイズが与えられた場合はmemcpyのようにすべてをコピーします。ソース文字列にヌルバイトがある場合は、その後の内容もコピーされます。 – athre0z

+0

@SethCarnegieはい、その理由を説明を追加しました。おそらく、このコンストラクタはOPに必要なものではありません –

3

STLのstd::stringクラスには、文字列内にヌル文字を含めることができます("xxx\0yyy"は長さが7の完全に有効な文字列です)。これは、ヌル終了については何も知らないことを意味します(ほとんど、ほとんどの場合、Cの文字列から/への変換があります)。言い換えれば、STLにはstrncpyの代替手段はありません。

const char *ptr = nameSra.pSection->pRawData->constPtr<char>(nameSra.offset); 
m_exportName.assign(ptr, strnlen(ptr, nameSra.numBytesToSectionsEnd)); 

または

const char *ptr = nameSra.pSection->pRawData->constPtr<char>(nameSra.offset); 
m_exportName.reserve(nameSra.numBytesToSectionsEnd); 
for (int i = 0; i < nameSra.numBytesToSectionsEnd && ptr[i]; i++) 
    m_exportName += ptr[i]; 
3

C++標準ライブラリにはstrncpyする正確な同等のがあります:

まだ短いコードであなたの目標を達成するには、いくつかの方法があります。 ?

私は間違いないでしょう!

つまり、終端の0に達するまで、あるバッファから別のバッファに文字列をコピーするという意味ですか?

ああ、それはstrncpy()が何をするかではない - あるいは少なくともそれはそれがないすべてのではありません。

strncpy()には、宛先バッファのサイズnを指定し、最大でn文字をコピーできます。それが行く限り、それは問題ありません。ソース文字列の長さ( "length"が終端文字より前にある文字数として定義された "'\0'")がnを超える場合、宛先バッファには付加的に\0'が埋め込まれます。そして、ソース文字列がnを超える場合、長さがの場合、終端記号'\0'はコピーされません

strncpy()関数は、初期のUnixシステムがディレクトリエントリにファイル名を格納する方法のために設計されました.14バイトの固定サイズのバッファで、最大14文字の名前を保持できます。 (編集:私は100%その意志がそのデザインの実際の動機であるとは確信していません)それはおそらく文字列関数ではなく、strcpy()の "より安全な"変形ではありません。

あなたは1がstrncpy()を想定かもしれないものと同等のものを達成することができます

strncat()を使用して(名前を与えられた)ん:

char dest[SOME_SIZE]; 
dest[0] = '\0'; 
strncat(dest, source_string, SOME_SIZE); 

これは常に'\0' -terminate宛先バッファ、およびそれはしません不パッドを持ちます余分な'\0'バイト。

あなたはそれに相当するstd::stringを実際に探していますか?

編集:上記を書いた後、私はthis rantをブログに投稿しました。

+0

私はこれらの事実を知っています(ゼロ詰め物を除いて)が、私のニーズを満たすために見つけることができた標準C/C++ライブラリの「最高の」機能でした。最初の投稿にある私の例で見ることができるように、私は終端のヌルバイトを手動で追加しました。 'strncat'はあて先文字列の最初のヌルバイトを検索しないで、長さが超過していないかどうかをチェックしながらヌルバイトを見つけた正確にその位置に追加を開始します。したがって、私は手動でnullに私のターゲットバッファの最初のバイトを設定しなければならなかったでしょうか? – athre0z

0

これに相当するものはありません。自分自身をロールバックする必要がありますstrncpy

それはstrncpyをの、完全に同等ではありませんが、文字列の部分文字列コンストラクタは、あなたがやりたいことができ
#include <cstring> 
#include <string> 

std::string strncpy(const char* str, const size_t n) 
{ 
    if (str == NULL || n == 0) 
    { 
     return std::string(); 
    } 

    return std::string(str, std::min(std::strlen(str), n)); 
} 
1

(最後に私のノートを参照してください):

std::string(const std::string& other, 
      size_type pos, 
      size_type count = std::string::npos, 
      const Allocator& alloc = Allocator()); 

は、サブの文字列を構築します[ pos、pos + count)を返します。 count == nposか、要求された部分文字列が文字列の最後まで続く場合、結果の部分文字列は[pos、size())です。

出典:http://www.cplusplus.com/reference/string/string/string/

例:

#include <iostream> 
#include <string> 
#include <cstring> 
int main() 
{ 
    std::string s0 ("Initial string"); 
    std::string s1 (s0, 0, 40); // count is bigger than s0's length 
    std::string s2 (40, 'a'); // the 'a' characters will be overwritten 
    strncpy(&s2[0], s0.c_str(), s2.size()); 
    std::cout << "s1: '" << s1 << "' (size=" << s1.size() << ")" << std::endl; 
    std::cout << "s2: '" << s2 << "' (size=" << s2.size() << ")" << std::endl; 
    return 0; 
} 

出力:strncpyを持つ

s1: 'Initial string' (size=14) 
s2: 'Initial string' (size=40) 

違い:

  • 文字列コンストラクタは常にNULL終端文字を結果に追加しますが、strncpyは結果にNULL文字を付加しません。
  • 要求されたカウントの前にヌル終了文字に達した場合、文字列コンストラクタは結果を0で埋めます。
関連する問題