2010-05-28 73 views
5

Tôi hiện đang làm việc trong một cơ sở mã nơi các địa chỉ IPv4 được biểu diễn dưới dạng con trỏ tới u_int8. Các nhà điều hành bình đẳng được thực hiện như thế này:So sánh nhanh các mảng char?

bool Ipv4Address::operator==(const u_int8 * inAddress) const 
{ 
    return (*(u_int32*) this->myBytes == *(u_int32*) inAddress); 
} 

Đây có lẽ là giải pháp nhịn ăn, nhưng nó gây ra các cảnh báo trình biên dịch GCC:

ipv4address.cpp:65: warning: dereferencing type-punned pointer will break strict-aliasing rules 

Làm thế nào tôi có thể viết lại việc so sánh một cách chính xác mà không vi phạm quy định nghiêm ngặt-aliasing và không mất điểm hiệu suất?

Tôi đã xem xét sử dụng một trong hai memcmp hoặc macro này:

#define IS_EQUAL(a, b) \ 
    (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]) 

Tôi nghĩ rằng vĩ mô là giải pháp nhanh nhất.

Bạn đề xuất điều gì?

Cập nhật
Tôi chỉ đọc bài viết Squeezing performance out of memcmp usage sẽ giải thích cách trình biên dịch (Visual Studio, nhưng có lẽ cũng GCC) có thể tối ưu hóa !memcmp(..) cuộc gọi.

+1

Bạn đã thử các tùy chọn khác nhau và đánh giá chúng để xem cái nào thực sự là nhanh nhất? –

+0

@Nick Meyer, chưa, nhưng đó là một gợi ý tốt. – StackedCrooked

Trả lời

10

tôi sẽ đi cho memcmp()

  1. Đó là khả năng di chuyển
  2. Tôi thường cố gắng không để thông minh hơn trình biên dịch/ngôn ngữ của tôi. Bạn đang cố gắng so sánh nội dung bộ nhớ và (tùy thuộc vào tùy chọn trình biên dịch quá) việc thực hiện memcmp() nên là cách hiệu quả nhất để làm điều đó.

Cũng nghĩ rằng nếu trình biên dịch của bạn không inline memcmp(), bạn sẽ bị ảnh hưởng bối cảnh chức năng chuyển

Bạn có chắc chắn bạn cần để tối ưu hóa quá khó? Bạn đã kiểm tra xem chương trình của bạn có dành phần lớn thời gian để thực hiện loại hoạt động đó không?

+2

Yep, 'std :: memcmp()' là những gì std lib có để so sánh mảng built-in. +1 từ tôi. Nếu hồ sơ cho thấy nó quá chậm trên một kiến ​​trúc nhất định, bạn luôn có thể quay lại và thay đổi nó. Tôi nghi ngờ nó, mặc dù. – sbi

+1

Là một lập trình viên tốt có nghĩa là biết cách sử dụng các công cụ được cung cấp trong bộ công cụ tiêu chuẩn. Ngoài ra, tối ưu hóa sớm là gốc rễ của mọi điều ác. Tôi biết những âm thanh như phản hồi sách giáo khoa, nhưng chúng đều rất quan trọng và không được sử dụng, ngay cả khi tốt nhất chúng ta vào thời điểm đó, rằng chúng đáng để lặp lại ... một lần nữa ... và một lần nữa ... – corsiKa

+1

So sánh địa chỉ IP ' uint8' bởi 'uint8' cũng di động. Số lượng nhỏ các so sánh thường hiệu quả hơn so với một cuộc gọi hàm thư viện; mặc dù chỉ có hồ sơ hoặc danh sách ngôn ngữ lắp ráp sẽ hiển thị bằng chứng. –

3

Lý do bạn nhận được lỗi từ GCC là bất kỳ thứ gì dài hơn 1 byte đều thích hợp với địa chỉ là bội số của kích thước đối tượng. Một số nguyên 32 bit thích bắt đầu trên các ranh giới 32 bit. Biến số char (đã ký, chưa ký hoặc đồng bằng), có thể nằm trên bất kỳ ranh giới byte nào, chẳng hạn như 3 không phát tốt cho các lần tìm nạp 32 bit của một bộ xử lý.

Trong trường hợp của bạn, với 4 byte (32 bit), có thể có nhiều chi phí hơn khi gọi memcmp so với mã để thực sự so sánh các byte.

Hãy thử điều này:

bool Ipv4Address::operator==(const u_int8 * inAddress) const 
{ 
    return myBytes[0] == inAddress[0] 
     && myBytes[1] == inAddress[1] 
     && myBytes[2] == inAddress[2] 
     && myBytes[3] == inAddress[3]; 
} 

Look Mom, thành viên mã chức năng mà không sử dụng this->!

Về hiệu quả, mã này có thể được thực thi cùng lúc khi cuộc gọi được thực hiện đến memcpy và trả lại được thực hiện từ nó (không thực hiện nội dung memcpy). Điều này giả định rằng memcpy không được gạch chân. Biết cách các thư viện trình biên dịch được viết cho các trường hợp chung và lớn, tôi nghi ngờ rằng mã này vẫn nhỏ hơn và nhanh hơn một phiên bản nội tuyến của memcpy.Mặc dù bằng chứng là in danh sách lắp ráp của hai phiên bản và so sánh.

Edit:
Lưu ý: tuyên bố thực hiện như nội tuyến hoặc đặt mã trong khai báo lớp, sẽ là tốt hơn so với quy định một macro nguy hiểm. Nó sẽ an toàn hơn và chứa cùng một lượng mã. Tôi thích phiên bản phương thức nội tuyến vì nó dễ đọc hơn và dễ bảo trì hơn.