2016-06-27 4 views
6

मैं ioctl सी ++ से उस ड्राइवर में कॉल कर रहा हूं जिसमें मेरा स्वामित्व/रखरखाव नहीं है, और यदि कोई साफ, "सुरक्षित-आश" तंत्र है तो मैं इसे हल करने का प्रयास कर रहा हूं कुछ बदसूरत संरचना आवंटन के साथ निपटने के लिए आवश्यक है। कुछ संरचनाओं केबदसूरत सी संरचना आवंटन के लिए आधुनिक सी ++ पैटर्न

नीचे Slimmed संस्करण शामिल

// IOCTL expects an instance of this structure "first" 
typedef struct { 
    int param1; 
    int param2; 
} s_ioctl_request; 

//... followed by an instance of this. If attr_length 
// is > sizeof(s_attr_header), more data is allowed to follow. 
typedef struct { 
    uint32_t attr_length; 
    uint32_t attr_type; 
} s_attr_header; 

// Example that uses more data than just the header. 
typedef struct { 
    s_attr_header hdr; 
    uint32_t attr_param; 
} s_attr_type1; 

// Another example. 
typedef struct { 
    s_attr_header hdr; 
    uint32_t attr_param1; 
    uint32_t attr_param2; 
} s_attr_type2; 

ioctl की आवश्यकता है कि s_ioctl_request तुरंत एक s_attr_header द्वारा पालन किया जाना, या अन्य struct यह युक्त, जहां attr_length बाइट में बाहरी struct के आकार को तैयार है।

C में, ioctl के लिए एक आवरण लिखने के लिए यह इन पंक्तियों के साथ कुछ के माध्यम से किया जाएगा:

int do_ugly_ioctl(int fd, int p1, int p2, s_attr_header * attr) 
{ 
    int res;  
    // Allocate enough memory for both structures. 
    s_ioctl_request *req = malloc(sizeof(*req) + attr->hdr.attr_length); 

    // Copy the 2nd, (variable length) structure after the first. 
    memcpy(((char*)req) + sizeof(*req), attr, attr->hdr.attr_length); 

    // Modify params as necessary 
    req->param1 = p1; 
    req->param2 = p2; 

    // Make the driver call, free mem, and return result. 
    res = ioctl(fd, SOME_IOCTL_ID, req); 
    free(req); 
    return res; 
} 

// Example invocation. 
s_attr_type1 a1; 
a1.hdr.attr_length = sizeof(a1); 
a1.hdr.attr_type = 1; 
do_ugly_ioctl(fd, 10, 20, &a1); 

एक जोड़े विकल्प के बारे में सोच रहा हूँ, कर रहे हैं:

  1. फेंक आधुनिक सी ++ - खिड़की से बाहर निकलता है, और ठीक वही करता है जो मैंने ऊपर दिखाया है।

  2. एक std :: वेक्टर के साथ भंडारण का आवंटन, तो जिसके परिणामस्वरूप std :: वेक्टर :: डेटा() सूचक के साथ बदसूरत डाले तो कम से कम मैं new[]/delete[] या malloc/free नहीं कर रहा हूँ है।

  3. प्रत्येक s_attr_type* के लिए एक अद्वितीय रैपर विधि बनाएं जो अपनी "विशेष" संरचना का उपयोग करती है। यह "सुरक्षित" लगता है, यानी इसे लपेटने के लिए रैपर विधि के उपयोगकर्ता के लिए कम से कम संभावना है। और बोनस अंक, पास-दर-रेफरी की अनुमति देता है।

विधि # 3 उदाहरण:

int do_ugly_ioctl(fd, int param1, int param2, s_attr_type2& attr){ 
    struct RequestData { 
     s_ioctl_request ioreq; 
     s_attr_type2 attr; 
    }; 
    RequestData r; 
    r.ioreq.param1 = param1; 
    r.ioreq.param2 = param2; 
    r.attr   = attr; 
    r.attr.hdr.attr_length = sizeof(attr); // Might as well enforce this here. 
    ioctl(fd, SOME_IOCTL_ID, (void*) &r); 
} 

तो मैं कुछ सवाल यहाँ लगता है कि कर रहे हैं:

  • यह सेल्सियस तक ++ "इसके लायक" है - इस समस्या का समाधान ize? (जैसा कि अधिक त्रुटि प्रवण सी प्रत्यारोपण पर निर्भर करने के विरोध में)।

  • यदि मैं विधि # 3 या इसी तरह के साथ जाता हूं, तो क्या मैं इस कार्य का टेम्पलेट बनाने के लिए <type_traits> के साथ कुछ भी कर सकता हूं और केवल पहले सदस्य के रूप में s_attr_header के साथ structs स्वीकार करता हूं?

  • कोई अन्य शानदार विचार?

+0

सी रैपर को कोड की 8 लाइनों की आवश्यकता होती है। सी ++ रैपर की आवश्यकता है 10. मैं ज्यादा सुधार देखने में विफल रहता हूं। –

+0

विकल्प 2 सिर्फ std :: वेक्टर के अंदर आवंटन छुपा रहा है, इसलिए इसमें कोई सुधार नहीं है। वास्तव में, विकल्प 2 एक भयानक समाधान है। –

+0

@CareyGregory मैं नहीं कहूंगा कि यह छिपा हुआ है क्योंकि प्रत्येक सी ++ - प्रोग्रामर जानता है कि वेक्टर क्या करता है। यह इसे encapsulated कहते हैं। – Jens

उत्तर

3

पूरी तरह से इसके लायक है, और आपका समाधान काफी अच्छा है। एकाधिक संरचनाओं को संयोजित करते समय अतिरिक्त पैडिंग होने से बचने के लिए आप अपनी संरचनाओं को packed (इसे प्राप्त करने के लिए कंपाइलर एक्सटेंशन) के रूप में घोषित करना चाहेंगे।

आप कन्स्ट्रक्टर के भीतर संरचना का आकार भी सेट कर सकते हैं।

struct RequestData 
{ 
     RequestData() : ioreq{}, attr{} 
     { 
     attr.hdr.attr_length = sizeof(attr); 
     } 
     s_ioctl_request ioreq; 
     s_attr_type2 attr; 
}; 

अपने दूसरे प्रश्न के विषय में, आप दो में काम विभाजित सकता है, यह भी अच्छा नहीं है, लेकिन यह आसान है और अगर आप एक सही हेडर के बिना कुछ गुजरती हैं, यह एक संकलक त्रुटि को बढ़ावा मिलेगा:

template<typename Attr> 
int do_ugly_ioctl(fd, int param1, int param2, Attr& attr){ 
    struct RequestData { 
     s_ioctl_request ioreq; 
     Attr attr; 
    }; 
    RequestData r; 
    r.ioreq.param1 = param1; 
    r.ioreq.param2 = param2; 
    s_attr_header hdr = Attr.hdr; //this will lead to compilation error if the type is not what we expect 
    (void) hdr; 
    r.attr  = attr; 
    r.attr.hdr.attr_length = sizeof(attr); // Might as well enforce this here. 
    ioctl(fd, SOME_IOCTL_ID, (void*) &r); 
} 
+0

तथ्य यह है कि हेडर सदस्य तक पहुंचने से एक त्रुटि होती है जब मेरी विधि # 3 में मेरा मानसिक "अनुपलब्ध लिंक" नहीं होता है। –

संबंधित मुद्दे