आप सी में समानता के लिए संरचना की तुलना कैसे करते हैं?


जवाबों:


196

सी ऐसा करने के लिए कोई भाषा सुविधाएं प्रदान नहीं करता है - आपको इसे स्वयं करना होगा और सदस्य द्वारा प्रत्येक संरचना के सदस्य की तुलना करनी होगी।


19
अगर 2 संरचनाओं के चर को कॉलोक के साथ आरंभिक किया जाता है या वे 0 से सेट होते हैं तो आप अपनी 2 संरचनाओं की तुलना मेम्कंप से कर सकते हैं और संरचना कचरा के बारे में कोई चिंता नहीं है और यह आपको समय अर्जित करने की अनुमति देगा
MOHAMED

21
@MOHAMED की तुलना फ्लोटिंग पॉइंट फ़ील्ड के साथ 0.0, -0.0 NaNकरना एक समस्या है memcmp()। बाइनरी प्रतिनिधित्व में भिन्न होने वाले पॉइंटर्स एक ही स्थान (जैसे DOS: seg: ऑफसेट) की ओर इशारा कर सकते हैं और इसी तरह समान हैं। कुछ प्रणालियों में कई अशक्त बिंदु होते हैं जो समान रूप से तुलना करते हैं। intअनावश्यक और अतिक्रमण के साथ -0 और अस्थायी बिंदु प्रकारों के साथ अस्पष्ट के लिए भी । (इंटेल लॉन्ग डबल, दशमलव 64, आदि) इन मुद्दों से कोई फर्क नहीं पड़ता है कि calloc()इसका उपयोग किया जाता है या नहीं या पैडिंग।
chux -

2
@chux किसी भी आधुनिक 32- या 64- बिट सिस्टम पर मुझे पता है, एकमात्र मुद्दा फ्लोटिंग पॉइंट के साथ है।
डेमी

2
यदि आप आश्चर्य करते हैं कि ==संरचनाओं के साथ काम क्यों नहीं किया जा रहा है (मेरी तरह), तो कृपया देखें stackoverflow.com/questions/46995631/…
stefanct

4
@ डेमी: आज। C प्रोग्रामर के लिए 10 वीं आज्ञा है 'तू पूर्वाभास करना, त्याग करना और वीभत्स विधर्म का त्याग करना, जो दावा करता है कि "समस्त संसार का एक वैक्स" ...'। इसे "सभी दुनिया के एक पीसी" के साथ बदलना एक सुधार नहीं है।
मार्टिन बोनर

110

आप का उपयोग करने के लिए परीक्षा हो सकती है memcmp(&a, &b, sizeof(struct foo)), लेकिन यह सभी स्थितियों में काम नहीं कर सकता है। संकलक एक संरचना में संरेखण बफर स्थान जोड़ सकता है, और बफर स्थान में पड़े मेमोरी स्थानों पर पाए जाने वाले मान किसी विशेष मूल्य के होने की गारंटी नहीं है।

लेकिन, यदि आप उपयोग करने से पहले संरचनाओं का उपयोग callocया memsetपूर्ण आकार देते हैं, तो आप उथले तुलना कर सकते हैं (यदि आपकी संरचना में संकेत होते हैं, तो यह केवल तभी मेल करेगा जब संकेत उसी ओर इशारा कर रहे हों)।memcmp


19
बंद करें, क्योंकि यह "लगभग सभी" संकलक पर काम करता है, लेकिन काफी नहीं। C90 में 6.2.1.6.4 की जाँच करें: "एक ही वस्तु प्रतिनिधित्व के साथ दो मान (NaN के अलावा) बराबर की तुलना करते हैं, लेकिन समान की तुलना करने वाले मूल्यों में अलग-अलग ऑब्जेक्ट प्रतिनिधित्व हो सकते हैं।"
स्टीव जेसप

22
"BOOL" फ़ील्ड पर विचार करें। समानता के संदर्भ में, कोई भी गैर-शून्य BOOL प्रत्येक गैर-शून्य BOOL मान के बराबर है। तो जबकि 1 और 2 दोनों TRUE हो सकते हैं और इसलिए बराबर, मेम्कैंप विफल हो जाएगा।
ajs410

4
आपके लिए @JSalazar आसान हो सकता है, लेकिन कंपाइलर और सीपीयू के लिए बहुत कठिन और इस तरह बहुत धीमा। आपको क्यों लगता है कि संकलक पहली जगह में पैडिंग जोड़ते हैं? निश्चित रूप से कुछ भी नहीं के लिए स्मृति को बर्बाद करने के लिए नहीं;)
मिकी

4
@ डेमेट्री: उदाहरण के लिए फ्लोट का मान धनात्मक और ऋणात्मक शून्य की तुलना किसी भी IEEE फ्लोट कार्यान्वयन पर बराबर होती है, लेकिन उनके पास समान ऑब्जेक्ट प्रतिनिधित्व नहीं है। इसलिए वास्तव में मुझे यह नहीं कहना चाहिए कि यह "लगभग सभी संकलक" पर काम करता है, यह किसी भी कार्यान्वयन पर विफल होगा जो आपको एक नकारात्मक शून्य स्टोर करने देता है। जिस समय मैंने टिप्पणी की, मैं शायद मज़ेदार पूर्णांक अभ्यावेदन के बारे में सोच रहा था।
स्टीव जेसोप

4
@ डेमेट्री: लेकिन कई में फ़्लोट्स होते हैं, और प्रश्नकर्ता पूछता है कि "आप स्ट्रक्चर्स की तुलना कैसे करते हैं", "न कि आप उन स्ट्रक्चर्स की तुलना कैसे करते हैं जिनमें फ़्लोट्स नहीं होते हैं"। यह उत्तर कहता है कि आप उथले तुलना कर सकते हैं memcmpबशर्ते कि मेमोरी पहले साफ़ हो गई हो। जो काम करने के करीब है लेकिन सही नहीं है। Ofc प्रश्न भी "समानता" को परिभाषित नहीं करता है, इसलिए यदि आप इसका अर्थ "ऑब्जेक्ट प्रतिनिधित्व की बाइट-वार समानता" लेते हैं, तो memcmpठीक यही करता है (चाहे मेमोरी क्लियर हो या नहीं)।
स्टीव जेसोप

22

यदि आप इसे बहुत कुछ करते हैं तो मैं एक ऐसा कार्य लिखने का सुझाव दूंगा जो दो संरचनाओं की तुलना करता है। इस तरह, यदि आप कभी संरचना को बदलते हैं तो आपको केवल एक ही स्थान पर तुलना को बदलना होगा।

यह कैसे करना है के रूप में .... आपको प्रत्येक तत्व की व्यक्तिगत रूप से तुलना करने की आवश्यकता है


1
मैं एक अलग फ़ंक्शन लिखूंगा भले ही मैं इसे केवल एक बार ही उपयोग करूं।
सैम

18

आप स्ट्रक्चर्स में फ़ील्ड के बीच संभावित बेतरतीब पैडिंग कैरेक्टर के कारण समानता के लिए स्ट्रक्चर्स की तुलना करने के लिए मेम्कैंप का उपयोग नहीं कर सकते।

  // bad
  memcmp(&struct1, &struct2, sizeof(struct1));

इस तरह की संरचना के लिए उपरोक्त विफल होगा:

typedef struct Foo {
  char a;
  /* padding */
  double d;
  /* padding */
  char e;
  /* padding */
  int f;
} Foo ;

आपको सुरक्षित रहने के लिए सदस्य-वार तुलना का उपयोग करना होगा।


25
डबल के बाद पैडिंग होने के लिए अनजाने में; चार डबल के तुरंत बाद पूरी तरह से पर्याप्त रूप से संरेखित किया जाएगा।
जोनाथन लेफ्लर

7

@Greg सही है कि किसी को सामान्य मामले में स्पष्ट तुलना कार्य लिखना चाहिए।

memcmpयदि इसका उपयोग करना संभव है :

  • संरचना में कोई फ़्लोटिंग-पॉइंट फ़ील्ड नहीं होती हैं जो संभवतः होती हैं NaN
  • स्ट्रक्चर्स में कोई पैडिंग नहीं होती है ( -Wpaddedइसे जांचने के लिए क्लैंग के साथ उपयोग करें) या स्ट्रक्चर्स को स्पष्ट रूप से इनिशियलाइज़ेशन के साथ शुरू किया memsetजाता है।
  • कोई भी सदस्य प्रकार (जैसे कि विंडोज BOOL) में अलग-अलग लेकिन समान मूल्य नहीं हैं।

जब तक आप एम्बेडेड सिस्टम के लिए प्रोग्रामिंग नहीं कर रहे हैं (या उन पर इस्तेमाल होने वाली लाइब्रेरी लिख रहे हैं), मैं सी मानक में कोने के कुछ मामलों के बारे में चिंता नहीं करूंगा। निकट बनाम दूर सूचक भेद किसी भी 32- या 64-बिट डिवाइस पर मौजूद नहीं है। कोई भी गैर-एम्बेडेड सिस्टम जो मुझे पता है कि कई NULLपॉइंटर्स हैं।

एक अन्य विकल्प समानता कार्यों को ऑटो-जनरेट करना है। यदि आप अपनी संरचना परिभाषाओं को सरल तरीके से रखते हैं, तो सरल संरचना परिभाषाओं को संभालने के लिए सरल पाठ प्रसंस्करण का उपयोग करना संभव है। आप सामान्य मामले के लिए libclang का उपयोग कर सकते हैं - चूंकि यह क्लैंग के रूप में एक ही दृश्यपटल का उपयोग करता है, यह सभी कोने के मामलों को सही ढंग से (बैरिंग कीड़े) को संभालता है।

मैंने ऐसी कोड जनरेशन लाइब्रेरी नहीं देखी है। हालाँकि, यह अपेक्षाकृत सरल प्रतीत होता है।

हालांकि, यह भी मामला है कि इस तरह के उत्पन्न समानता कार्य अक्सर आवेदन स्तर पर गलत काम करेंगे। उदाहरण के लिए, UNICODE_STRINGविंडोज में दो संरचनाओं की तुलना उथली या गहराई से की जानी चाहिए ?


2
स्पष्ट रूप से memsetआदि के साथ संरचना को
आरम्भ करना

4

ध्यान दें कि जब तक आप सभी सदस्यों को एक बार में आरंभ नहीं करते हैं, तब तक आप पैडिंग की चिंता किए बिना नॉन स्टैटिक स्ट्रेक्चर पर मेम्कैंप () का उपयोग कर सकते हैं। यह C90 द्वारा परिभाषित किया गया है:

http://www.pixelbeat.org/programming/gcc/auto_init.html


1
क्या यह वास्तव में निर्दिष्ट है जो {0, }किसी भी पेडिंग बाइट को शून्य करेगा?
अलनीतक

आंशिक रूप से प्रारंभ structs के लिए बाइट्स पैडिंग के रूप में ऊपर के लिंक पर प्रदर्शन किया कम से कम शून्य, और कम से जीसीसी stackoverflow.com/questions/13056364/... जानकारी है कि C11 निर्दिष्ट करता है कि व्यवहार।
15

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

2

यह इस बात पर निर्भर करता है कि आप जो प्रश्न पूछ रहे हैं वह है:

  1. क्या ये दोनों संरचनाएं एक ही वस्तु हैं?
  2. क्या उनका एक ही मूल्य है?

यह पता लगाने के लिए कि क्या वे समान वस्तु हैं, समानता के लिए दो संरचनाओं की ओर संकेत करते हैं। यदि आप सामान्य रूप से यह पता लगाना चाहते हैं कि क्या उनका समान मूल्य है तो आपको गहरी तुलना करनी होगी। इसमें सभी सदस्यों की तुलना करना शामिल है। यदि सदस्य अन्य संरचनाओं के संकेत हैं, तो आपको उन संरचनाओं में भी पुनरावृत्ति करने की आवश्यकता है।

विशेष मामले में जहां संरचनाओं में पॉइंटर्स नहीं होते हैं, आप प्रत्येक डेटा में मौजूद डेटा की एक बिटवाइज़ तुलना करने के लिए एक मेम्कप कर सकते हैं, बिना यह जाने कि डेटा का क्या मतलब है।

सुनिश्चित करें कि आप जानते हैं कि प्रत्येक सदस्य के लिए sure बराबरी ’का क्या अर्थ है - यह फ़्लोट-पॉइंट मान या उपयोगकर्ता-परिभाषित प्रकार की बात होने पर, इन्टल्स के लिए अधिक सूक्ष्म है।


2

memcmpसंरचना की तुलना नहीं करता है, memcmpबाइनरी की तुलना करता है, और संरचना में हमेशा कचरा होता है, इसलिए यह तुलना में हमेशा गलत निकलता है।

तत्व की तुलना अपने सुरक्षित तत्व से करें और असफल न हों।


1
यदि 2 संरचना चर को कॉलोक के साथ आरम्भ किया जाता है या वे 0 द्वारा सेट किए जाते हैं तो आप अपने 2 संरचनाओं की तुलना मेम्कंप से कर सकते हैं और संरचना कचरा के बारे में कोई चिंता नहीं है और यह आपको समय अर्जित करने की अनुमति देगा
MOHAMED

1

यदि संरचनाओं में केवल आदिम हैं या यदि आप सख्त समानता में रुचि रखते हैं तो आप ऐसा कुछ कर सकते हैं:

int my_struct_cmp (const संरचना my_struct * lhs, const संरचना my_struct * rhs)
{
    वापसी मेम्कम्प (lhs, rsh, sizeof (स्ट्रक्चर my_struct));
}

हालाँकि, यदि आपकी संरचना में अन्य संरचनाओं या यूनियनों के संकेत होते हैं, तो आपको एक फ़ंक्शन लिखना होगा जो प्राथमिकताओं की ठीक से तुलना करता है और अन्य संरचनाओं के खिलाफ तुलनात्मक कॉल को उपयुक्त बनाता है।

हालाँकि, अवगत रहें, कि आपको ADT इनिशियलाइज़ेशन के भाग के रूप में स्ट्रक्चर्स की मेमोरी रेंज को शून्य करने के लिए मेमसेट (&, a, sizeof (स्ट्रक्चर माय_स्ट्रैक), 1) का उपयोग करना चाहिए था।


-1

यदि 2 संरचना चर को कॉलोक के साथ आरम्भ किया जाता है या वे 0 द्वारा सेट किए जाते हैं तो आप अपने 2 संरचनाओं की तुलना मेम्कंप से कर सकते हैं और संरचना कचरा के बारे में कोई चिंता नहीं है और यह आपको समय अर्जित करने की अनुमति देगा


-2

यह अनुपालन उदाहरण Microsoft Visual Studio से #pragma पैक कंपाइलर एक्सटेंशन का उपयोग करता है ताकि यह सुनिश्चित हो सके कि संरचना सदस्यों को कसकर पैक किया गया है:

#include <string.h>

#pragma pack(push, 1)
struct s {
  char c;
  int i;
  char buffer[13];
};
#pragma pack(pop)

void compare(const struct s *left, const struct s *right) { 
  if (0 == memcmp(left, right, sizeof(struct s))) {
    /* ... */
  }
}

1
यह वास्तव में सही है। लेकिन ज्यादातर मामलों में आप नहीं चाहते कि आपकी संरचना पैक हो! बहुत सारे निर्देश, और संकेत, आवश्यकता है कि इनपुट डेटा शब्द-संरेखित है। यदि यह नहीं है, तो संकलक को वास्तविक निर्देश को निष्पादित करने से पहले डेटा को कॉपी और पुन: संरेखित करने के लिए अतिरिक्त निर्देश जोड़ने की आवश्यकता है। यदि कंपाइलर डेटा को पुनः संरेखित नहीं करेगा तो सीपीयू एक अपवाद को फेंक देगा।
रुद अल्थुइज़ेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.