7

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

私はすでにこのトピックに関して多くの検索を行い、興味深いトピックもいくつか見つけましたが、それらの人々はすべて 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++ 標準ライブラリに実装されている解決策があれば、それを望んでいます。

4

7 に答える 7

11

作成したいバッファstringに少なくとも 1 つの NUL が含まれていることがわかっている場合は、それをコンストラクタに渡すだけです。

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

std::string s(buffer);

// s contains "hello"

よくわからない場合は、最初の null の文字列を検索し、コンストラクターに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

2 番目のバージョン (バッファに NUL がなくても常に機能する) をきちんとした小さな関数にラップできます。

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);
}

ただし、注意すべき点が 1 つあります。引数が 1 つのコンストラクタ aconst char*を単独で渡すと、NUL が見つかるまで実行されます。の単一引数コンストラクタを使用する場合、バッファに少なくとも 1 つの NUL があることを知っておくことが重要ですstd::string

残念ながら (または幸いなことに)、strncpyforに完全に相当するものは組み込まれていませんstd::string

于 2012-01-16T19:46:57.537 に答える
3

C++ 標準ライブラリに strncpy とまったく同等のものはありますか?

私は確かにそうではないことを願っています!

終端の 0 に到達するまで、文字列をあるバッファから別のバッファにコピーする関数を意味しますか?

ああ、でもそれだけではありません。strncpy()少なくとも、それだけではありませ

strncpy()nコピー先バッファのサイズを指定でき、最大n文字数までコピーできます。そこまではいいです。ソース文字列の長さ (「長さ」は、終端の に先行する文字数として定義される'\0') を超えるn場合、宛先バッファーは追加\0'の s でパディングされますが、これはほとんど役に立ちません。また、ソース文字列の長さがこれを超える場合n終端'\0'はコピーされません

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

strncpy()を使用して、(名前を指定して)想定するものと同等のものを実現できますstrncat()

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

これは常に'\0'宛先バッファを終了し、不必要に余分な'\0'バイトを埋め込むことはありません。

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

編集:上記を書いた後、この暴言をブログに投稿しました。

于 2012-01-16T20:14:43.287 に答える
3

STLのstd::stringクラスでは、文字列内に null 文字を含めることができます ("xxx\0yyy"は長さ 7 の完全に有効な文字列です)。これは、null 終了について何も知らないことを意味します (ほとんどの場合、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];
于 2012-01-16T19:50:25.937 に答える
1

std::stringには、使用できる次の署名を持つコンストラクターがあります。

string ( const char * s, size_t n );

次の説明:

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

于 2012-01-16T19:39:19.733 に答える
1

組み込みの同等物はありません。自分でロールする必要があります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));
}
于 2014-08-06T05:59:40.547 に答える
0

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

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

これにより、次のドキュメントに従って正確なコピーが生成されます:http ://www.cplusplus.com/reference/string/string/string/

于 2012-01-16T19:32:27.890 に答える