2012-02-16 32 views
5
#define offsetof(type, member) ((size_t)(&((type *)0)->member)) 

Tôi không hiểu những gì đang (&((type *)0)->member) này chính xác nói với tôi .....Macro này chính xác là gì?

đây loại có thể là một cấu trúc hay cái gì khác ?? ...

Cụ thể hơn những gì là 0 kể tôi ở đây??

+0

bản sao có thể có của [Tại sao mã C này hoạt động?] (Http://stackoverflow.com/questions/713963/why-does-this-c-code-work) –

Trả lời

2

tôi phá vỡ nó xuống như thế này:

  1. (type *)0 - đúc 0 đến một con trỏ để gõ "type". tức là hãy tưởng tượng trong một phút rằng có một đối tượng thuộc loại "type" tại địa chỉ bộ nhớ 0.

  2. ->member - nhìn vào đối tượng cho trường được gọi là member.

  3. & - lấy địa chỉ đó.

Bạn cũng có thể viết nó như thế này:

((size_t)((&((type *)x)->member) - x)) 

Nhưng chúng ta đang lừa dối và sử dụng 0 để không có bù đắp cất cánh ở cuối.

+0

Ya, tôi hiểu rằng nó mang lại cho tôi sự bù đắp của cấu trúc, nhưng tôi không nhận được lý do tại sao chúng tôi cung cấp cho các loại * trên đây .... nó nên làm việc cho (& ((loại) 0) -> thành viên) ... Tôi thiếu một cái gì đó. ??? – Invictus

+0

Bit '- x' không nên nằm trong dấu ngoặc đơn trước phép diễn' size_t', nếu không nó sẽ trừ 'x' từ' type * '- có thể không giống như trừ' x' khỏi một số. –

+0

Chris - Tôi đặt trong nhiều dấu ngoặc đơn để đối phó với điều đó và để làm cho nó đơn giản hơn - nhìn gần hơn :-). – mattjgalloway

6

Điều này nhằm xác định độ lệch của trường cấu trúc. Nó hoạt động bằng cách sử dụng 0 như địa chỉ của các cấu trúc, sau đó yêu cầu cho địa chỉ của trường:

(type *)0 

là 0 như một con trỏ đến type

&((type *)0)->member 

được địa chỉ của rằng giả thuyết cấu trúc của member hội viên. Nếu địa chỉ của cấu trúc là 0, thì địa chỉ của thành viên giống như phần bù đắp của phần đầu của cấu trúc.

((size_t)(&((type *)0)->member)) 

là địa chỉ đó được chuyển thành size_t là loại thích hợp cho khoản chênh lệch.

+0

Ya, tôi hiểu nó đang cung cấp tôi bù đắp của cấu trúc, nhưng tôi không nhận được lý do tại sao chúng tôi cung cấp cho các loại * trên đây .... nó nên làm việc cho (& ((loại) 0) -> thành viên) ... tôi thiếu cái gì đó. ??? – Invictus

+0

Có. '(type) 0' không phải là lvalue và không có địa chỉ. Bạn cần đối tượng mà địa chỉ của nó (không có giá trị!) Là 0. BTW, tôi khá chắc chắn rằng toàn bộ điều là UB. – asaelr

+0

@asaelr - Thật kỳ quặc, tiêu chuẩn tối ưu hóa '& * (loại *) 0' và' & ((loại *) 0) [x] 'nhưng không phải' & ((loại *) 0) -> thành viên' - nhưng nó "thường" hoạt động. Trên các nền tảng không có, sử dụng '(type *) 1024' sẽ hầu như luôn hoạt động - nó phải được căn chỉnh cho hầu hết mọi loại. Chỉ cần nhớ trừ số đó từ kết quả cuối cùng ở cuối macro. –

3

Macro đang nhập địa chỉ (0) vào loại được khai báo ("loại"), sau đó truy cập vào trường ("thành viên") và nhận địa chỉ. Kết quả là địa chỉ của trường, được bù đắp từ địa chỉ 0, cung cấp hình thức bù đắp sự bắt đầu của kiểu (cấu trúc/công đoàn) cho trường.

+0

Tôi nguyền rủa kỹ năng đánh máy của mình! – Jamie

+0

Ya, tôi nhận được rằng nó cho tôi sự bù đắp của cấu trúc, nhưng tôi không nhận được lý do tại sao chúng tôi cung cấp loại * ở đây .... nó sẽ làm việc cho (& ((loại) 0) -> thành viên) ... tui bỏ lỡ điều gì vậy. ??? – Invictus

+1

Hằng số của bạn được lưu trữ ở đâu? Thay đổi số không thành số tùy ý - '123' nói, theo cách nào đó, bạn sẽ yêu cầu trình biên dịch cung cấp cho bạn địa chỉ của hằng số cộng với độ lệch của một thành viên chứ không phải địa chỉ của _address_ cộng với độ lệch của thành viên , đó là lý do bạn chọn làm con trỏ. – Jamie