2012-01-16 31 views
7

chính xác tương đương strncpy trong Thư viện chuẩn C++ không? Tôi có nghĩa là một chức năng, mà sao chép một chuỗi từ một bộ đệm khác cho đến khi nó chạm vào chấm dứt 0? Ví dụ khi tôi phải phân tích chuỗi từ một nguồn không an toàn, chẳng hạn như các gói TCP, vì vậy tôi có thể thực hiện kiểm tra chiều dài trong khi đối phó dữ liệu.tương đương strncpy cho std :: string?

Tôi đã tìm kiếm rất nhiều về chủ đề này và tôi cũng tìm thấy một số chủ đề thú vị, nhưng tất cả những người đó đều hài lòng với std :: string :: assign, cũng có thể lấy kích thước ký tự để sao chép tham số. Vấn đề của tôi với chức năng này là, nó không thực hiện bất kỳ kiểm tra nếu một null chấm dứt đã được nhấn - nó có kích thước nhất định nghiêm trọng và sao chép dữ liệu giống như memcpy sẽ làm điều đó vào bộ đệm của chuỗi. Bằng cách này có nhiều bộ nhớ hơn được phân bổ và sao chép hơn là nó phải được thực hiện, nếu có một kiểm tra trong khi đối phó.  

Đó là cách tôi đang làm việc xung quanh vấn đề này hiện nay, nhưng có một số overhead tôi muốn tránh:

// 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; 

Đoạn mã này là một phần của phân tích cú pháp của tôi cho PE-mã nhị phân (của việc phân tích cú pháp bảng xuất khẩu, chính xác). rva2sra chuyển đổi địa chỉ ảo tương đối thành địa chỉ có liên quan đến PE. Cấu trúc ExportDirectory_t chứa RVA đối với tên xuất của tệp nhị phân, trong đó nên là một chuỗi không bị chấm dứt. Nhưng điều đó không phải lúc nào cũng phải như vậy - nếu ai đó thích nó, nó sẽ có thể bỏ qua số không kết thúc mà sẽ làm cho chương trình của tôi chạy vào bộ nhớ không thuộc về phần, nơi nó cuối cùng sẽ sụp đổ (Trong trường hợp tốt nhất...).

Sẽ không có vấn đề lớn khi thực hiện một chức năng như vậy, nhưng tôi thích nó nếu có giải pháp cho việc này được thực hiện trong Thư viện chuẩn C++.

+7

'std :: string's không bị hủy. Bạn có muốn một bản sao của chuỗi, hoặc chỉ là một bản sao của tất cả mọi thứ lên đến byte null đầu tiên (có thể hoặc có thể không có)? –

+0

Ồ, tốt để biết. Tôi muốn sao chép tất cả mọi thứ lên đến byte null đầu tiên. – athre0z

+1

[Hãy cẩn thận những gì bạn yêu cầu.] (Http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html) –

Trả lời

11

Nếu bạn biết rằng bộ đệm bạn muốn thực hiện một string ra có ít nhất một NUL trong nó sau đó bạn chỉ có thể vượt qua nó để các nhà xây dựng:

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

std::string s(buffer); 

// s contains "hello" 

Nếu bạn không chắc chắn, sau đó bạn chỉ phải tìm kiếm các chuỗi cho null đầu tiên, và nói với các nhà xây dựng của string để tạo ra một bản sao của dữ liệu hơn nhiều:

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 

bạn có thể w rap phiên bản thứ hai (mà luôn luôn làm việc, ngay cả khi không có một NUL trong bộ đệm) lên thành một chức năng nhỏ gọn gàng:

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

Nhưng có một điều cần lưu ý: nếu bạn tay các nhà xây dựng đơn lập luận một chính nó là const char*, nó sẽ đi cho đến khi nó tìm thấy một NUL. Điều quan trọng là bạn biết có ít nhất một NUL trong bộ đệm nếu bạn sử dụng hàm tạo đối số đơn của std::string.

Thật không may (hoặc may mắn thay), không được xây dựng hoàn toàn tương đương với strncpy cho std::string.

+0

Cảm ơn bạn, đó là những gì tôi đang tìm kiếm. – athre0z

1

Sử dụng lớp constructor:

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

này sẽ mang lại một bản sao chính xác, theo tài liệu này: http://www.cplusplus.com/reference/string/string/string/

+3

OP không tìm kiếm cho 'strcpy' nhưng' strncpy'. – pmr

+0

@pmr: OP làm rõ anh ta chỉ muốn lên đến byte NULL đầu tiên. –

+0

Vâng, đó cũng là sự thật. –

1

std::string có một constructor có chữ ký tiếp theo mà có thể được sử dụng:

string (const char * s, size_t n); 

với mô tả tiếp theo:

Nội dung được khởi tạo thành bản sao của chuỗi được tạo thành bởi các ký tự đầu tiên trong mảng ký tự được chỉ bởi s.

+0

Lưu ý rằng điều này sẽ không dừng lại ở byte rỗng (nó nói "mảng ký tự", không phải "chuỗi C"). Điều đó có thể hoặc không thể là những gì bạn muốn. –

+2

Cảm ơn bạn đã trả lời, nhưng đó không phải là điều tôi muốn biết. Hàm khởi tạo sao chép mọi thứ cho đến khi nó chạm vào byte null đầu tiên HOẶC, nếu kích thước được cho, mọi thứ, giống như memcpy. Nếu có một byte null trong chuỗi nguồn của tôi, nội dung sau khi nó cũng được sao chép. – athre0z

+0

@SethCarnegie Có, đó là lý do tôi thêm mô tả. Có lẽ nhà xây dựng này không phải là những gì OP cần –

3

Lớp std::string trong STL có thể chứa các ký tự rỗng trong chuỗi ("xxx\0yyy" là chuỗi có độ dài hoàn toàn hợp lệ 7). Điều này có nghĩa là nó không biết gì về việc chấm dứt null (gần như là, có các chuyển đổi từ/đến chuỗi C). Nói cách khác, không có thay thế trong STL cho strncpy.

Có một vài cách để vẫn đạt được mục tiêu của bạn với một mã ngắn hơn:

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

hoặc

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ó một chính xác tương đương với strncpy trong Thư viện chuẩn C++ ?

Tôi chắc chắn hy vọng là không!

Tôi có nghĩa là một hàm sao chép chuỗi từ bộ đệm này sang bộ đệm khác cho đến khi nó kết thúc bằng 0?

Ah, nhưng đó không phải những gì strncpy() không - hoặc ít nhất là nó không phải là tất cả nó.

strncpy() cho phép bạn chỉ định kích thước, n, của bộ đệm đích và bản sao tối đa n ký tự. Đó là tốt như xa như nó đi. Nếu độ dài của chuỗi nguồn ("độ dài" được xác định là số ký tự trước khi kết thúc '\0') vượt quá n, bộ đệm đích được thêm với \0' s bổ sung, cái gì đó ít khi hữu ích. Và nếu độ dài nếu chuỗi nguồn vượt quá n thì việc chấm dứt '\0' không được sao chép.

Chức năng strncpy() được thiết kế cho cách hệ thống Unix lưu trữ tên tệp trong mục nhập thư mục: dưới dạng bộ đệm kích thước cố định 14 byte có thể chứa tối đa 14 ký tự. (EDIT: Tôi không chắc chắn 100% đó là động lực thực sự cho thiết kế của nó.) Nó được cho là không phải là một hàm chuỗi, và nó không chỉ là một biến thể "an toàn hơn" của strcpy().

Bạn có thể đạt tương đương với những gì người ta có thể giả định strncpy() không (được đặt tên) sử dụng strncat():

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

này sẽ luôn '\0' -terminate điểm đến đệm, và nó sẽ không không cần thiết pad nó với thêm '\0' byte.

Bạn có thực sự đang tìm kiếm một số std::string tương đương không?

EDIT: Sau khi tôi đã viết ở trên, tôi đã đăng this rant trên blog của mình.

+0

Tôi nhận thức được những sự kiện này (ngoại trừ điều về padding zero), nhưng đó là chức năng 'tốt nhất' trong Thư viện chuẩn C/C++ mà tôi có thể tìm thấy để đáp ứng nhu cầu của mình. Như bạn có thể thấy trong ví dụ của tôi được đưa ra trong bài đăng đầu tiên, tôi đã thêm byte null kết thúc theo cách thủ công. Không tìm kiếm 'strncat' cho byte null đầu tiên trong chuỗi đích và sau đó bắt đầu chắp thêm tại vị trí chính xác mà nó tìm thấy byte rỗng trong khi kiểm tra nếu độ dài bị vượt quá và cuối cùng thêm một null kết thúc? Vì vậy, tôi đã phải đặt byte đầu tiên của bộ đệm đích của tôi thành null theo cách thủ công, tôi có đúng không? – athre0z

0

Không có tích hợp sẵn. Bạn phải cuộn strncpy của riêng mình.

#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

constructor chuỗi con của chuỗi có thể làm những gì bạn muốn, mặc dù nó không phải là một tương đương chính xác của strncpy (xem ghi chú của tôi ở cuối):

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

Constructs chuỗi với một chuỗi [ pos, pos + count) của người khác. Nếu count == npos hoặc nếu chuỗi con được yêu cầu kéo dài qua cuối chuỗi, chuỗi con kết quả là [pos, size()).

Nguồn: http://www.cplusplus.com/reference/string/string/string/

Ví dụ:

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

Output:

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

khác biệt với strncpy:

  • constructor chuỗi luôn gắn thêm một ký tự kết thúc null vào kết quả, strncpy không;
  • hàm tạo chuỗi không tạo kết quả bằng 0 nếu một ký tự kết thúc null đạt được trước số đếm được yêu cầu, strncpy sẽ thực hiện.