[英]strncpy equivalent for std::string?
在C ++標准庫中是否與strncpy 完全等效? 我的意思是一個函數,它將一個字符串從一個緩沖區復制到另一個緩沖區,直到它到達終止0? 例如,當我必須從不安全的源解析字符串時,例如TCP數據包,所以我能夠在處理數據時執行長度檢查。
我已經搜索了很多關於這個主題的內容,我也發現了一些有趣的話題,但所有這些人都對std :: string :: assign感到滿意,它也可以將一個字符大小復制為參數。 我對這個函數的問題是,它不會執行任何檢查,如果已經命中了終止空值 - 它需要給定的大小嚴重並且像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節相對地址。 structure contains the RVA to the export name of the binary, which should be a zero-terminated string. 結構包含二進制文件的導出名稱的RVA,該名稱應為零終止字符串。 但事情並非總是如此 - 如果有人想要它,它將能夠省略終止零,這將使我的程序運行到不屬於該部分的內存中,它最終會崩潰(在最好的情況下...)。
我自己實現這樣的功能不是一個大問題,但如果在C ++標准庫中實現了這個解決方案,我更喜歡它。
如果你知道你想要創建一個string
的緩沖區中至少有一個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
您可以將第二個版本(即使緩沖區中沒有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);
}
但有一點需要注意: 如果你將單參數構造const char*
單獨設置為一個const char*
,它將一直運行直到它找到一個NUL。 重要的是,如果使用std::string
的單參數構造函數,則知道緩沖區中至少有一個NUL 。
不幸的是(或幸運的是), std::string
沒有內置完美的strncpy
等價物。
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];
在C ++標准庫中是否與strncpy 完全等效?
我當然希望不是!
我的意思是一個函數,它將一個字符串從一個緩沖區復制到另一個緩沖區,直到它到達終止0?
啊,但這不是strncpy()
所做的 - 或者至少它不是全部 。
strncpy()
允許您指定目標緩沖區的大小n
,並最多復制n
字符。 就目前而言,這很好。 如果源字符串的長度(“長度”定義為終止'\\0'
之前的字符數)超過n
,則目標緩沖區將填充額外的\\0'
,這很少有用。 如果源字符串的長度超過n
,則不會復制終止'\\0'
。
strncpy()
函數是為早期Unix系統在目錄條目中存儲文件名的方式設計的:作為一個14字節的固定大小的緩沖區,最多可以容納14個字符的名稱。 (編輯:我不是100%確定這是它設計的實際動機。)它可以說不是字符串函數,它不僅僅是strcpy()
的“更安全”變體。
您可以使用strncat()
實現與strncpy()
所做的相同的操作(給定名稱strncat()
:
char dest[SOME_SIZE];
dest[0] = '\0';
strncat(dest, source_string, SOME_SIZE);
這將始終'\\0'
終止目標緩沖區,並且它不會不必要地用額外的'\\0'
字節填充它。
你真的在尋找與之相當的std::string
嗎?
編輯:在我寫完上述內容之后,我在我的博客上發布了這個咆哮 。
字符串的子串構造函數可以做你想要的,盡管它不是strncpy的完全等價物(參見我最后的注釋):
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;
}
輸出:
s1: 'Initial string' (size=14)
s2: 'Initial string' (size=40)
與strncpy的差異:
std :: string有一個構造函數,可以使用下一個簽名:
string ( const char * s, size_t n );
有下一個描述:
內容被初始化為由s指向的字符數組中的前n個字符形成的字符串的副本。
沒有內置的等價物。 你必須滾動你自己的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));
}
使用類的構造函數:
string::string str1("Hello world!");
string::string str2(str1);
根據此文檔,這將產生一個精確的副本: http : //www.cplusplus.com/reference/string/string/string/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.