2009-09-08 34 views
10

Đôi khi cần phải so sánh độ dài của chuỗi với hằng số.
Ví dụ:Biên dịch "strlen()" có hiệu quả không?

if (line.length() > 2) 
{ 
    // Do something... 
} 

Nhưng tôi đang cố gắng để tránh sử dụng "kỳ diệu" hằng số trong mã.
Thông thường tôi sử dụng mã ví dụ:

if (line.length() > strlen("[]")) 
{ 
    // Do something... 
} 

Nó là dễ đọc hơn, nhưng không hiệu quả vì các lời gọi hàm.
tôi đã viết chức năng mẫu như sau:

template<size_t N> 
size_t _lenof(const char (&)[N]) 
{ 
    return N - 1; 
} 

template<size_t N> 
size_t _lenof(const wchar_t (&)[N]) 
{ 
    return N - 1; 
} 

// Using: 
if (line.length() > _lenof("[]")) 
{ 
    // Do something... 
} 

Trong một thông cáo xây dựng (VisualStudio 2008) nó tạo mã khá tốt:

cmp dword ptr [esp+27Ch],2 
jbe 011D7FA5 

Và điều đáng mừng là trình biên dịch không bao gồm "[]" chuỗi trong đầu ra nhị phân.

Đây có phải là một tối ưu hóa trình biên dịch cụ thể hay là một hành vi phổ biến?

+2

bạn có thể sử dụng một mẫu cho tất cả các loại mảng, một cái gì đó nói dối: 'template size_t _lenof (const T (&) [N]) {return N - 1; } ', vẫn hoạt động giống như ví dụ của bạn. –

+2

@Evan Teran: ý tưởng hay, nhưng các hàm này chỉ có ý nghĩa đối với các chuỗi (mảng char/wchar_t) vì chấm dứt '\ 0'. Chức năng của bạn sẽ làm việc cho int [10] và trả về 9 - Tôi không nghĩ rằng nó có ý nghĩa;) – Dmitriy

+0

@Dmitriy: thực sự –

Trả lời

4

Khả năng căn chỉnh cuộc gọi hàm là cả tối ưu hóa theo trình biên dịch cụ thể một hành vi phổ biến. Đó là, nhiều trình biên dịch có thể làm điều đó, nhưng chúng không bắt buộc phải làm như vậy.

+0

Tối ưu hóa mong muốn không (chỉ) yêu cầu nội tuyến. Nó đòi hỏi độ dài của chuỗi được tính toán tại thời gian biên dịch. –

+0

Đó không thực sự là một tối ưu hóa, mặc dù. Độ dài sẽ không được tính trong thời gian chạy và vẫn gọi bất kỳ hàm '_lenof' nào. Không phải là tiêu chuẩn * yêu cầu * triển khai để cung cấp cho chuỗi literals loại 'const char [N]'? Và không phải là giá trị của kiểu như vậy cần thiết để làm cho trình biên dịch suy ra các đối số của hàm mẫu là 'N'? –

+0

Xin lỗi, tôi đã hiểu lầm câu trả lời của bạn là gì - vì một lý do nào đó mà tôi đã nói về "không hiệu quả vì cuộc gọi hàm [strlen]". Nếu một trình biên dịch không thể nội dòng _lenof, thì nó có thể không thể nội tuyến bất cứ điều gì, và sẽ là một trình biên dịch C++ khá nghèo nói chung. Bất kỳ việc sử dụng nghiêm túc các khuôn mẫu nào sẽ là ác mộng ... –

12

Tại sao không

 
sizeof "[]" - 1; 

(trừ một cho null dấu Bạn có thể làm sizeof "[]" -. Sizeof '\ 0', nhưng sizeof '\ 0' thường là sizeof (int) trong C, và "- 1" là hoàn toàn có thể đọc được)

+0

sẽ không hoạt động đối với các chuỗi rộng (ví dụ: L "[]"). – Dmitriy

+1

có thể được cố định cho các chuỗi rộng. Một cái gì đó như: '(sizeof (L" [] ")/sizeof (L" ")) - 1' –

+0

@Evan Teran: có, nhưng bạn nên sử dụng macro để làm cho nó dễ đọc hơn. Các macro IMHO có nhiều kiểu C hơn nhưng không phải C++ – Dmitriy

-7
#define TWO 2 
#define STRING_LENGTH 2 
/* ... etc ... */ 

Nghiêm túc, tại sao đi qua tất cả rắc rối này chỉ để tránh gõ 2.? Tôi thành thật nghĩ rằng bạn đang làm cho mã của bạn ít đọc được, và các lập trình viên khác sẽ nhìn chằm chằm vào bạn như bạn đang snorting cà phê được sử dụng từ bộ lọc.

+0

nó chỉ là ví dụ. Trong mã thực, nó trông giống như "một số chuỗi". Bạn sẽ đếm số ký tự trong trường hợp này? :) – Dmitriy

+0

Có, tôi. Và tôi sẽ. Và tôi làm. –

+2

@Jed Smith: :) Bạn có chắc chắn rằng bạn không quên thay đổi định nghĩa macro nếu chuỗi thay đổi? – Dmitriy

2

Tôi nghĩ hầu hết các trình biên dịch sẽ tối ưu hóa nó đi khi tối ưu hóa được bật. Nếu chúng bị vô hiệu hóa, nó có thể làm chậm chương trình của bạn xuống nhiều hơn mức cần thiết.

Tôi thích chức năng mẫu của bạn hơn vì chúng được đảm bảo không gọi strlen khi chạy. Tất nhiên, chứ không phải là văn bản chức năng riêng biệt cho charwchar_t, bạn có thể thêm một mẫu đối số, và có được một chức năng mà làm việc cho bất kỳ loại:

template <typename Char_t, int len> 
int static_strlen(const Char_t (&)[N] array){ 
    return len/sizeof(Char_t) - 1; 
} 

(Như đã đề cập trong ý kiến, điều này sẽ cho kết quả hài hước nếu thông qua một loạt các int, nhưng bạn có khả năng làm điều đó không? Nó có nghĩa là cho chuỗi, sau khi tất cả)

Lưu ý cuối cùng, tên _strlenxấu. Tất cả tên tại phạm vi không gian tên bắt đầu bằng dấu gạch dưới được dành riêng cho việc triển khai. Bạn có nguy cơ một số xung đột đặt tên khó chịu.

Nhân tiện, tại sao "[]" ít hơn một hằng số ma thuật so với 2 là?

Trong cả hai trường hợp, đó là một nghĩa đen phải được thay đổi nếu định dạng của chuỗi được so sánh với thay đổi.

+0

Vì lý do nào đó, chức năng của bạn không xuất hiện nhanh hơn sử dụng strlen. Tuy nhiên, nó có vẻ nhanh hơn sử dụng std :: char_traits :: length, do đó, nó vẫn hữu ích vì strlen chỉ hoạt động trên mảng char. – leetNightshade

Các vấn đề liên quan