2013-12-17 7 views
5

का उपयोग कर सी में structs की तुलना करें मुझे पता है कि memcmp() का उपयोग उन संरचनाओं की तुलना करने के लिए नहीं किया जा सकता है जो memset() 0 से 0 प्रारंभिक पैडिंग के कारण नहीं हैं। हालांकि, मेरे कार्यक्रम में मेरे पास शुरुआत में कुछ अलग-अलग प्रकार के साथ एक संरचना है, फिर संरचना के अंत तक एक ही प्रकार के कई दर्जन हैं। मेरा विचार था कि पहले कुछ प्रकारों की मैन्युअल रूप से तुलना करें, फिर उसी टाइप किए गए सदस्यों के शेष संगत मेमोरी ब्लॉक पर memcmp() का उपयोग करें।memcmp() और पॉइंटर अंकगणित

मेरा सवाल है, संरचना मानक पैडिंग के बारे में सी मानक गारंटी क्या है? क्या मैं किसी भी या सभी कंपाइलरों पर भरोसेमंद इसे प्राप्त कर सकता हूं? क्या सी मानक समान प्रकार के सदस्यों के बीच स्ट्रक्चर पैडिंग डालने की अनुमति देता है?

रूप gcc साथ इरादा मैं अपने प्रस्तावित समाधान को लागू किया है, और यह वास्तव में काम करने के लिए लगता है:

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

struct foo 
{ 
    char a; 
    void *b; 
    int c; 
    int d; 
    int e; 
    int f; 
}; 

static void create_struct(struct foo *p) 
{ 
    p->a = 'a'; 
    p->b = NULL; 
    p->c = 1; 
    p->d = 2; 
    p->e = 3; 
    p->f = 4; 
} 

static int compare(struct foo *p1, struct foo *p2) 
{ 
    if (p1->a != p2->a) 
     return 1; 

    if (p1->b != p2->b) 
     return 1; 

    return 
     /* Note the typecasts to char * so we don't get a size in ints. */ 
     memcmp(
      /* A pointer to the start of the same type members. */ 
      &(p1->c), 
      &(p2->c), 
      /* A pointer to the start of the last element to be compared. */ 
      (char *)&(p2->f) 
      /* Plus its size to compare until the end of the last element. */ 
      +sizeof(p2->f) 
      /* Minus the first element, so only c..f are compared. */ 
      -(char *)&(p2->c) 
     ) != 0; 
} 

int main(int argc, char **argv) 
{ 
    struct foo *p1, *p2; 
    int ret; 

    /* The loop is to ensure there isn't a fluke with uninitialized padding 
    * being the same. 
    */ 
    do 
    { 
     p1 = malloc(sizeof(struct foo)); 
     p2 = malloc(sizeof(struct foo)); 

     create_struct(p1); 
     create_struct(p2); 

     ret = compare(p1, p2); 

     free(p1); 
     free(p2); 

     if (ret) 
      puts("no match"); 
     else 
      puts("match"); 
    } 
    while (!ret); 

    return 0; 
} 
+0

माइनर: चूंकि आपकी पॉइंटर तुलना 0 या 1 लौट रही है, इसलिए 'memcmp() '' memcmp()! = 0' के साथ' memcmp() '0 या 1 को बीमा करने का सुझाव दिया गया है। – chux

+0

@chux अच्छा विचार, सुझाव के लिए धन्यवाद। – John

उत्तर

4

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

0

दुख की बात है, वहाँ कोई सी मानक (है कि मैंने कभी सुना है) आप संरचना को नियंत्रित करने के लिए अनुमति देता है गद्दी। इस तथ्य स्वत: आवंटन है कि इस

struct something val = { 0 }; 

तरह आरंभ नहीं हो जाता कि val में सभी सदस्यों का कारण होगा 0 के लिए शुरू किया जाना है। लेकिन बीच में पैडिंग कार्यान्वयन के लिए छोड़ दिया गया है।

ऐसे कंपाइलर एक्सटेंशन हैं जिनका उपयोग आप जीसीसी के __attribute__((packed)) जैसे सभी संरचना पैडिंग को खत्म करने के लिए कर सकते हैं, लेकिन इसके अलावा आप नुकसान में हो सकते हैं।

मुझे यह भी पता है कि बिना किसी बड़े अनुकूलन के, अधिकांश कंपाइलर्स ज्यादातर मामलों में संरचना पैडिंग जोड़ने के लिए परेशान नहीं होंगे, जो यह बताएगा कि यह जीसीसी के तहत क्यों काम करता है।

कहा, यदि आपका संरचना के सदस्यों को इस

struct something { char onebyte; int fourbyte; }; 

की तरह अजीब संरेखण समस्याओं का कारण वे संकलक onebyte सदस्य के बाद गद्दी जोड़ने के लिए fourbyte सदस्य के संरेखण आवश्यकताओं को पूरा करने का कारण होगा।

+1

यह: 'कुछ वैल्यू = {0};' पहले सदस्य को 0 से प्रारंभ करता है और फिर डिफ़ॉल्ट शेष सदस्यों को प्रारंभ करता है (संभवतः 0 के साथ यदि यह उनका डिफ़ॉल्ट है)। 'कुछ वैल्यू = {};' डिफ़ॉल्ट सभी सदस्यों को इनलाइन करता है जो अधिक सामान्य है क्योंकि पहला आइटम एक अभिन्न सदस्य हो सकता है या नहीं। –

+0

@JerryJeremiah सच है, लेकिन यह विचार बेहतर हो जाता है। – randomusername

+0

'gdb' के साथ जांच करते समय मैंने पाया कि' चार ए 'के बाद जोड़े गए 7 पैडिंग बाइट्स थे, जो पूरे सिस्टम को 32 सिस्टम के बाइट्स बनाते थे (25 की बजाय, जो '__attribute __ ((__ पैक __) के मामले में था) । पूरी संरचना पर एक सरल 'memcmp() 'का उपयोग करते समय, वे निश्चित रूप से बराबर नहीं थे। – John

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