संपादित करें: माफ करना, यह देर से, मैं लिखने की त्रुटियों की एक बहुत कुछ कर दिया है होना चाहिए।
वे शुद्ध मजाक हैं! :) अंतर यह है कि list_for_each_entry
तोड़ देगा यदि आप सूची को पुन: करते समय कुछ हटाते हैं और list_for_each_entry_safe
नहीं होगा (बेशक, कुछ अतिरिक्त CPU निर्देशों की कीमत पर)।
कर्नेल दोगुनी-लिंक्ड सूचियों (जो मुझे लगता है कि आप समझते हैं) पर बस गए हैं, हालांकि सूची में एक सिंगल लिंक्ड सूची कार्यान्वयन है। अपनी सूची बस है:
struct list_head {
struct list_head *next;
struct list_head *prev;
};
नोट है कि एक ही struct दोनों सूची के "सिर" के साथ-साथ प्रत्येक नोड के लिए प्रयोग किया जाता है। जब सूची खाली होती है, तो सिर का next
और prev
सदस्य केवल अपने सिर को इंगित करते हैं। इस प्रकार, सूची को पुन: सक्रिय करना केवल next
सदस्य से शुरू करने की प्रक्रिया है और एक नोड को कॉल करना, जब तक कि यह prev
(जब आप रुकें) के समान पता हो। अन्यथा, आपके for
शरीर को बुलाया जाता है और आप container_of()
मैक्रो का उपयोग अपने वास्तविक संरचना में पॉइंटर प्राप्त करने और इसके साथ खेलने के लिए कर सकते हैं। फिर, for
के तीसरे क्षेत्र में, हम बस अगले next
पर जाएं।
संपादित करें: व्हाउप्स, मैं क्षमा चाहता हूं, आपने पैरामीटर की व्याख्या के लिए कहा था। खैर, अगर मैं इसके लिए किसी के शब्द लेने के बजाए आप सीधे थे तो मैं इसे सीधे देखता हूं। उन लोगों के लिए, मैं Kernel API docs स्वयं का सुझाव दूंगा, जो कम से कम लिंक्ड सूची लाइब्रेरी के लिए मौजूद है। मैं एक पैच सेट प्राप्त करने की कोशिश कर रहा हूं जो उन्हें लाल-काले पेड़ पुस्तकालय के साथ भी जोड़ देगा, लेकिन सामान भरना काफी प्रक्रिया हो सकता है।
नोट के
इसके अलावा:
struct list_head my_actual_list;
struct my_struct {
struct list_head node;
/* some other members */
};
/* in a function body somewhere... */
struct list_head *i;
list_for_each(i, &my_actual_list) {
struct my_struct *obj = list_entry(i, struct my_struct, node);
// do something with obj
}
list_entry
, बस के लिए container_of
संपादित करें # 2
ठीक एक उपनाम है जवाब में इतना: http://kernelnewbies.org/FAQ/LinkedLists
यहां एक त्वरित उदाहरण है टिप्पणियों में आपके प्रश्न के लिए, मैं बस अपना जवाब विस्तारित करने जा रहा हूं। मैं वास्तव में इस अवधारणा को समझने में कठिनाई की सराहना कर सकता हूं क्योंकि सी ++ एसटीएल कंटेनर, सी सरणी आदि की तुलना में इसमें कुछ अजीब चीजें हैं, लेकिन एक बार जब आप मुहावरे के आदी हो जाते हैं, तो यह काफी स्वाभाविक प्रतीत होता है। अभी भी भविष्य में, मैं आपको सचमुच आग्रह करता हूं कि आप इन structs के लिए परिभाषा को देखना शुरू करें, & फ़ंक्शन स्वयं को मैक्रोज़ करें और एक साथ समझने की कोशिश कर रहे हैं, फिर प्रश्न पूछें।
तो सबसे पहले बंद, अपनी सूची में प्रत्येक नोड एक struct है कि प्रकार struct list_head
के एक सदस्य और सूची अपने स्वयं प्रकार struct list_head
का होता है। इस प्रकार, कंटेनर कौन है और इस मामले में निहित कौन है, इस बात पर निर्भर करता है कि उनका उपयोग कैसे किया जाता है, लेकिन आम तौर पर, इन सदस्यों को दिए गए नामों में व्यक्त किया जाएगा। इटरेटर का प्रकार struct list_head *
है। यहाँ एक उदाहरण है और मैं उनके बराबर कोड के साथ सामान्य कार्य & मैक्रो कॉल से बदल देंगे:
struct my_container {
struct list_head list;
int some_member;
/* etc. */
};
struct my_obj {
struct list_head node;
int some_member;
/* etc. */
};
void func() {
struct my_container container;
struct my_obj obj1, obj2;
struct list_head *i;
/* INIT_LIST_HEAD(&container.list); */
container.list.next = &container.list;
container.list.prev = &container.list;
/* list_add_tail(&obj1.node); */
container.list.prev = &obj1.node;
obj1.node.next = &container.list;
obj1.node.prev = &container.list;
container.list.next = &obj1.node;
/* list_add_tail(&obj2.node); */
container.list.prev = &obj2.node;
obj2.node.next = &container.list;
obj2.node.prev = &obj1.node;
obj1.node.next = &obj2.node;
/* list_for_each(i, &container.list) { */
for (i = container.list.next; i != &container.list; i = i->next) {
struct my_obj *obj = list_entry(i, struct my_obj, node);
/* do stuff */
}
}
Now go read! :)
मैं सुझाव है कि आप किताब लिनक्स कर्नेल को समझने पढ़ें। – stdcall
आपके सुझाव के लिए धन्यवाद, इस पुस्तक में सूची से संबंधित अच्छी सामग्री है .. – goodies