2011-04-25 22 views
6

सादा सी में अच्छी सुविधा है - शून्य प्रकार पॉइंटर्स, जिसे किसी भी डेटा प्रकार के सूचक के रूप में उपयोग किया जा सकता है।
लेकिन, मान मैं struct निम्नलिखित है:प्रकार शून्य शून्य


struct token { 
    int type; 
    void *value; 
}; 

जहां मूल्य क्षेत्र सरणी चार के लिए, या int करने के लिए, या कुछ और जा सकते हैं।
तो जब इस संरचना के नए उदाहरण आवंटित करते हैं, तो मुझे चाहिए:

1) इस संरचना के लिए स्मृति आवंटित करें;
2) मूल्य के लिए स्मृति आवंटित करें और इसे मूल्य फ़ील्ड में असाइन करें।

मेरा प्रश्न है - "सरणी प्रकार शून्य" घोषित करने के तरीके हैं, जिन्हें शून्य सूचक जैसे किसी अन्य प्रकार में डाला जा सकता है?

मैं चाहता हूं कि किसी भी प्रकार कास्टिंग करने की क्षमता के साथ "लचीला सदस्य सरणी" (सी 99 मानक के 6.7.2.1 में वर्णित) का उपयोग करना है।

कुछ इस तरह:


struct token { 
    int type; 
    void value[]; 
}; 

struct token *p = malloc(sizeof(struct token) + value_size); 
memcpy(p->value, val, value_size); 
... 
char *ptr = token->value; 

मैं token- घोषित मान लें कि> चार या पूर्णांक सरणी और जरूरत प्रकार के कास्टिंग बाद में इस काम करेंगे, लेकिन किसी के लिए बहुत भ्रामक है जो इस पढ़ा जाएगा हो सकता है के रूप में मूल्य बाद में कोड वास्तव में आप अपने टाइपकास्ट करने के लिए उन p.value [सूचकांक] = somethings है

struct token { 
    int type; 
    void *value; 
}; 

struct token p; 

p.value = malloc(value_size); 

p.value[0] = something; 
p.value[1] = something; 
... 

संपादित करें,:

+0

डबल पॉइंटर्स? 'Char []' का उपयोग करके –

+2

ठीक इमो है, क्योंकि 'sizeof (char) == 1' और आप कभी आश्चर्यचकित नहीं होंगे। आप सही प्रकार के साथ 'p-> value' तक पहुंचने के लिए मैक्रोज़ पर विचार करना चाह सकते हैं। –

उत्तर

1

मैं शायद यह करना होगा। और/या टाइपकास्ट करने के लिए एक संघ का उपयोग करें।

+0

इसका उपयोग करने से पहले आपको 'p.value' डालना होगा। –

+0

'p.value [0] = कुछ' संकलन-समय त्रुटि उत्पन्न करेगा, निश्चित रूप से? कोई 'शून्य * 'को अस्वीकार नहीं कर सकता है। –

+0

grin, आप मुझे इसे हराया ... जल्दी से संपादन प्राप्त करने की कोशिश कर रहा था। –

3

ठीक है, एक तरह से, लेकिन यह शायद नहीं कुछ तुम चाहते हो रहा है:

struct token { 
    // your fields 
    size_t item_size; 
    size_t length 
}; 

struct token *make_token(/* your arguments */, size_t item_size, size_t length) 
{ 
    struct token *t = malloc(sizeof *t + item_size * length); 
    if(t == NULL) return NULL; 
    t->item_size = item_size; 
    t->length = length; 
    // rest of initialization 
} 

निम्नलिखित मैक्रो सूचकांक के लिए अपने डेटा इस्तेमाल किया जा सकता (यह मानते हुए x एक struct token * है):

#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ? 
         (void *)(((char *)x[1]) + x->item_size * i) 
        : NULL : NULL) 

और , यदि आप चाहें, तो निम्न मैक्रो आपके make_token फ़ंक्शन को थोड़ा और अधिक सहज बनाने के लिए लपेट सकता है (या अधिक हैकिश, यदि आप इसके बारे में सोचते हैं):

#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l) 

उपयोग:

struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints 
... 
idx(p, 2, int) = 10; 
1

आप 'शून्य' आइटम की एक सरणी नहीं हो सकता है, लेकिन आप value_size जब आप करते हैं कि आप क्या चाहते की तरह कुछ करने के लिए, जब तक कि आप जानते हैं सक्षम होना चाहिए malloc। लेकिन यह सुंदर नहीं होगा।

struct token { 
     int type; 
     void *value;  
};  

value_size = sizeof(type)*item_count; 
struct token *p = malloc(sizeof(struct token) + value_size); 
//can't do memcpy: memcpy(p->value, val, value_size); 
//do this instead 
type* p = (type*)&(p->value); 
type* end = p+item_count; 
while (p<end) { *p++ = someItem; } 

ध्यान दें कि जब आप अतिरिक्त संग्रहण प्राप्त करना चाहते हैं तो आपको ऑपरेटर के अतिरिक्त पते की आवश्यकता है।

type *ptr = (type*)&(token->value); 

यह 'बर्बाद' होगा sizeof (शून्य *) बाइट्स, और value की मूल प्रकार वास्तव में बात तो आप भी एक छोटे आइटम का उपयोग कर सकते नहीं है,। मैं शायद typedef char placeholder; और उस प्रकार value बना सकता हूं।

0

निम्नलिखित संरचना आपकी मदद कर सकती है।

struct clib_object_t { 
void* raw_data; 
size_t size; 
}; 

struct clib_object_t* 
new_clib_object(void *inObject, size_t obj_size) { 
    struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t)); 
    if (! tmp) 
     return (struct clib_object_t*)0; 
    tmp->size  = obj_size; 
    tmp->raw_data = (void*)malloc(obj_size); 
    if (!tmp->raw_data) { 
     free (tmp); 
     return (struct clib_object_t*)0; 
    } 
    memcpy (tmp->raw_data, inObject, obj_size); 
    return tmp; 
} 

clib_error 
get_raw_clib_object (struct clib_object_t *inObject, void**elem) { 
    *elem = (void*)malloc(inObject->size); 
    if (! *elem) 
     return CLIB_ELEMENT_RETURN_ERROR; 
    memcpy (*elem, inObject->raw_data, inObject->size); 

    return CLIB_ERROR_SUCCESS; 
} 

अधिक जानकारी: clibutils

0

AShelly का जवाब आप यह कर सकते हैं पर विस्तार;

/** A buffer structure containing count entries of the given size. */ 
typedef struct { 
    size_t size; 
    int count; 
    void *buf; 
} buffer_t; 

/** Allocate a new buffer_t with "count" entries of "size" size. */ 
buffer_t *buffer_new(size_t size, int count) 
{ 
    buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size); 
    if (p) { 
     p->size = size; 
     p->count = count; 
    } 
    return p; 
} 

नोट के उपयोग "offsetof()" के बदले "sizeof()" जब स्मृति बर्बाद कर से बचने के लिए आवंटन "शून्य * buf," क्षेत्राकार। "Buf" का प्रकार कोई फर्क नहीं पड़ता है, लेकिन "शून्य *" का उपयोग करने का अर्थ है कि यह "पॉफ" फ़ील्ड को पॉइंटर के लिए बेहतर रूप से संरचना में संरेखित करेगा, यदि आवश्यक हो तो इससे पहले पैडिंग जोड़ना। यह आमतौर पर प्रविष्टियों के लिए बेहतर मेमोरी संरेखण देता है, खासकर अगर वे कम से कम एक सूचक के रूप में बड़े होते हैं।

बफर में प्रविष्टियों तक पहुंच इस तरह दिखती है;

/** Get a pointer to the i'th entry. */ 
void *buffer_get(buffer_t *t, int i) 
{ 
    return &t->buf + i * t->size; 
} 

नोट अतिरिक्त पते-के ऑपरेटर आवंटित प्रविष्टि स्मृति के लिए प्रारंभिक बिंदु के रूप में "buf" क्षेत्र का पता प्राप्त करने के लिए।

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