2009-08-25 24 views
9

Nói rằng tôi có một cấu trúc như sau ...C con trỏ vs truy cập thành viên trực tiếp cho struct

typedef struct { 
    int WheelCount; 
    double MaxSpeed; 
} Vehicle; 

... và tôi có một biến toàn cầu thuộc loại này (tôi cũng nhận thức được những cạm bẫy của globals, đây là cho một hệ thống nhúng, mà tôi đã không thiết kế, và mà họ là một điều đáng tiếc nhưng cần thiết.) Là nó nhanh hơn để truy cập vào các thành viên của cấu trúc trực tiếp hoặc thông qua một con trỏ? tức là

double LocalSpeed = MyGlobal.MaxSpeed; 

hoặc

double LocalSpeed = pMyGlobal->MaxSpeed; 

Một trong những nhiệm vụ của tôi là để đơn giản hóa và sửa chữa một hệ thống nhúng thời gian gần đây thừa hưởng.

+1

Con trỏ cung cấp cho bạn quyền truy cập trực tiếp đó là gì? Và một con trỏ chậm hơn. –

+3

-1 để hỏi về tối ưu hóa vi mô mà không cần điểm chuẩn trước. – bk1e

Trả lời

19

Nói chung, tôi muốn nói đi với các tùy chọn đầu tiên:

double LocalSpeed = MyGlobal.MaxSpeed; 

này có một ít dereference (bạn không tìm thấy con trỏ, sau đó dereferencing nó để có được vị trí của nó). Nó cũng đơn giản và dễ đọc hơn và duy trì, vì bạn không cần tạo biến con trỏ ngoài cấu trúc.

Điều đó đang được nói, tôi không nghĩ rằng bất kỳ sự khác biệt hiệu suất nào bạn thấy sẽ đáng chú ý, ngay cả trên một hệ thống nhúng. Cả hai sẽ là thời gian truy cập rất, rất nhanh.

+0

Tại sao các downvotes? Tôi muốn tò mò tại sao mọi người không đồng ý. –

+1

Tôi có Reed ở đây. Tham chiếu trực tiếp an toàn hơn, không yêu cầu kiểm tra NULL và lưu một thao tác dereferencing. Nội dung bộ nhớ của biến phải được truy cập anyways, vậy tại sao một tra cứu bổ sung. Một con trỏ sẽ giúp bạn không có gì nếu bạn đã có quyền truy cập trực tiếp vào biến đó. –

+0

Đối với các dereferencing con trỏ, đó là những gì tôi đã nghĩ, nó chỉ là một thời gian dài kể từ khi tôi đã phải đối phó với một trong hai C hoặc C + +. Cảm ơn các bạn vì lời khuyên của bạn. –

1

Tôi cho rằng, nếu điều này tạo ra sự khác biệt, điều đó sẽ phụ thuộc vào kiến ​​trúc.

1

Trong C, không nên có sự khác biệt hoặc hiệu suất không đáng kể.

sinh viên C được dạy:

pMyGlobal->MaxSpeed == (*pMyGlobal).MaxSpeed 

Bạn sẽ có thể so sánh tháo gỡ trong số họ cả để thuyết phục bản thân rằng họ là về cơ bản giống nhau, ngay cả khi bạn không phải là một lập trình viên hội-mã.

Nếu bạn đang tìm kiếm tối ưu hóa hiệu suất, tôi sẽ tìm ở nơi khác. Bạn sẽ không thể lưu đủ chu kỳ CPU với loại tối ưu hóa vi mô này.

Vì lý do phong cách, tôi thích ký hiệu Cấu trúc-Dot, đặc biệt là khi giao dịch với singleton-globals. Tôi thấy nó dễ đọc hơn nhiều.

+1

Câu hỏi không phải là về -> vs *, đó là về cách sử dụng một con trỏ ở nơi đầu tiên. –

+1

Câu hỏi đặt ra là: "Truy cập thành viên của cấu trúc trực tiếp hoặc thông qua con trỏ có nhanh hơn không?" Tôi tin rằng tôi đã giải quyết câu hỏi. – abelenky

8

Người đầu tiên phải nhanh hơn vì nó không yêu cầu dereferencing con trỏ. Sau đó, một lần nữa thats đúng cho x86 dựa trên hệ thống, không chắc chắn cho những người khác.

trên x86 đầu tiên sẽ dịch một cái gì đó như thế này

mov eax, [address of MyGlobal.MaxSpeed] 

và điều thứ hai sẽ là một cái gì đó như thế này

mov ebx, [address of pMyGlobal] 
mov eax, [ebx+sizeof(int)] 
1

Nói chung, truy cập vào các cấu trúc trực tiếp sẽ nhanh hơn, như nó sẽ không yêu cầu một dereference thêm con trỏ. Các dereference con trỏ có nghĩa là nó phải mất con trỏ (điều trong biến), tải bất cứ điều gì nó trỏ đến, sau đó hoạt động trên đó.

3

Trên nền tảng nhúng của bạn, có khả năng kiến ​​trúc được tối ưu hóa theo cách cơ bản để rửa và thậm chí nếu bạn không nhận thấy tác động hiệu suất nếu điều này được thực hiện trong một vòng lặp rất chặt chẽ .

Có thể có nhiều khu vực hoạt động rõ ràng hơn trong hệ thống của bạn.

3
struct dataStruct 
{ 
    double first; 
    double second; 
} data; 

int main() 
{ 
    dataStruct* pData = &data; 

    data.first = 9.0; 
    pData->second = 10.0; 
} 

Đây là sản phẩm lắp ráp sử dụng chế độ VS2008 phát hành:

data.first = 9.0; 
008D1000 fld   qword ptr [[email protected] (8D20F0h)] 

    pData->second = 10.0; 
008D1006 xor   eax,eax 
008D1008 fstp  qword ptr [data (8D3378h)] 
008D100E fld   qword ptr [[email protected] (8D20E8h)] 
008D1014 fstp  qword ptr [data+8 (8D3380h)] 
+1

Bây giờ nhắm mục tiêu nền tảng nhúng của mình. – Alan

+0

cài đặt tối ưu hóa là gì? –

+0

Điều này là sai. Thành viên đầu tiên của bạn sẽ luôn luôn giành chiến thắng theo định nghĩa của một struct (con trỏ của một struct cũng là một con trỏ của một thành viên đầu tiên). Bạn nên so sánh thứ hai so với giây. –

2

tháo rời, tháo rời, tháo rời ...

Tùy thuộc vào các dòng mã bạn không hiển thị chúng tôi có thể nếu con trỏ của bạn có phần tĩnh thì trình biên dịch tốt sẽ biết và tính toán địa chỉ cho cả hai. Nếu bạn không có tối ưu hóa thì toàn bộ cuộc thảo luận này bị tắt tiếng. Nó cũng phụ thuộc vào bộ xử lý bạn đang sử dụng, cả hai có thể được thực hiện với một lệnh duy nhất tùy thuộc vào bộ vi xử lý. Vì vậy, tôi làm theo các bước tối ưu hóa cơ bản:

1) tháo rời và kiểm tra 2) Thời gian thực hiện

Như đã đề cập ở trên dù mấu chốt là nó có thể là một trường hợp hai hướng dẫn thay vì một chi phí một đồng hồ đơn chu kỳ bạn sẽ không bao giờ thấy. Chất lượng của trình biên dịch và lựa chọn trình tối ưu hóa của bạn sẽ tạo ra sự khác biệt đáng kể về hiệu suất nhiều hơn là cố gắng tinh chỉnh một dòng mã với hy vọng cải thiện hiệu suất. Chuyển đổi trình biên dịch có thể cung cấp cho bạn 10-20% theo một trong hai hướng, đôi khi nhiều hơn. Như có thể thay đổi cờ tối ưu hóa của bạn, biến mọi thứ trên không làm cho mã nhanh nhất, đôi khi -O1 hoạt động tốt hơn -O3.

Hiểu được hai dòng mã đó tạo ra như thế nào và cách tối đa hóa hiệu suất từ ​​ngôn ngữ cấp cao đến từ việc biên dịch cho các bộ xử lý và tháo khác nhau bằng cách sử dụng các trình biên dịch khác nhau. Và quan trọng hơn là mã xung quanh các dòng trong câu hỏi đóng một vai trò lớn trong cách trình biên dịch tối ưu hóa phân khúc đó.

Sử dụng ví dụ của người khác về vấn đề này:

typedef struct 
{ 
    unsigned int first; 
    unsigned int second; 
} dataStruct; 

dataStruct data; 

int main() 
{ 
    dataStruct *pData = &data; 

    data.first = 9; 
    pData->second = 10; 

    return(0); 
} 

Với gcc (không phải là tuyệt vời một trình biên dịch) bạn nhận được:

mov r2, #10 
mov r1, #9 
stmia r3, {r1, r2} 

Vì vậy, cả hai dòng mã C được gia nhập vào một cửa hàng, vấn đề ở đây là ví dụ được sử dụng như một bài kiểm tra. Hai hàm riêng biệt sẽ tốt hơn một chút nhưng nó cần nhiều mã hơn xung quanh nó và con trỏ cần trỏ vào một số bộ nhớ khác để trình tối ưu hóa không nhận ra đó là địa chỉ tĩnh toàn cục, để kiểm tra điều này bạn cần phải truyền địa chỉ do đó trình biên dịch (cũng gcc) không thể tìm ra rằng nó là một địa chỉ tĩnh.

Hoặc không có tối ưu hóa, cùng một mã, cùng một trình biên dịch, không có sự khác biệt giữa con trỏ và trực tiếp.

mov r3, #9 
str r3, [r2, #0] 

mov r3, #10 
str r3, [r2, #4] 

Đây là những gì bạn mong đợi sẽ thấy tùy thuộc vào trình biên dịch và bộ xử lý, có thể không có sự khác biệt. Đối với bộ xử lý này ngay cả khi mã kiểm tra ẩn địa chỉ tĩnh cho con trỏ từ hàm, nó vẫn sẽ đun sôi xuống hai hướng dẫn. Nếu giá trị được lưu trữ trong phần tử cấu trúc đã được tải trong một thanh ghi thì nó sẽ là một hướng dẫn một trong hai cách, con trỏ hoặc trực tiếp.

Vì vậy, câu trả lời cho câu hỏi của bạn không phải là tuyệt đối ...nó phụ thuộc. tháo rời và thử nghiệm.

+0

sử dụng tăng gấp đôi thay vì ints chỉ có nghĩa là đăng ký nhiều hơn cửa hàng chính nó vẫn là một hướng dẫn duy nhất cho con trỏ hoặc truy cập trực tiếp, do đó, vẫn không có sự khác biệt, cho trình biên dịch này cho bộ xử lý cho phiên biên dịch này. –

+0

Điều này là sai. Thành viên đầu tiên của bạn sẽ luôn luôn giành chiến thắng theo định nghĩa của một struct (con trỏ của một struct cũng là một con trỏ của một thành viên đầu tiên). Bạn nên so sánh thứ hai so với giây. –

0

Truy cập thành viên trực tiếp nhanh hơn (đối với con trỏ, bạn sẽ nhận được một thao tác dereference con trỏ hơn, thường). Mặc dù tôi có một thời gian khó tưởng tượng nó trong một tình huống mà nó sẽ là một vấn đề, hiệu suất hay cách khác.

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