क्या gcc का __attribute __ ((पैक)) / #pragma पैक असुरक्षित है?


164

सी में, कंपाइलर एक संरचना के सदस्यों को उस क्रम में बाहर करेगा, जिसमें वे घोषित किए जाते हैं, जिसमें सदस्यों के बीच संभावित पैडिंग बाइट्स शामिल हैं, या अंतिम सदस्य के बाद, यह सुनिश्चित करने के लिए कि प्रत्येक सदस्य ठीक से संरेखित है।

gcc एक भाषा एक्सटेंशन प्रदान करता है __attribute__((packed)), जो कंपाइलर को पेडिंग न लगाने के लिए कहता है, जिससे स्ट्रक्चर सदस्यों को गलत जानकारी दी जा सकती है। उदाहरण के लिए, यदि सिस्टम सामान्य रूप से सभी की आवश्यकता intकी वस्तुओं 4 बाइट संरेखण के लिए, __attribute__((packed))पैदा कर सकता है intstruct सदस्यों अजीब ऑफसेट पर आवंटित किया जाना है।

जीसीसी दस्तावेज का हवाला देते हुए:

`पैक 'विशेषता निर्दिष्ट करती है कि एक चर या संरचना क्षेत्र में सबसे छोटा संभव संरेखण होना चाहिए - एक चर के लिए एक बाइट, और एक क्षेत्र के लिए एक बिट, जब तक आप` संरेखित' विशेषता के साथ एक बड़ा मूल्य निर्दिष्ट नहीं करते।

स्पष्ट रूप से इस एक्सटेंशन के उपयोग से डेटा की छोटी-छोटी आवश्यकताएं पूरी हो सकती हैं लेकिन धीमी कोड, क्योंकि कंपाइलर को (कुछ प्लेटफार्मों पर) एक गलत सदस्य को एक बार में बाइट एक्सेस करने के लिए कोड जनरेट करना होगा।

लेकिन क्या ऐसे कोई मामले हैं जहां यह असुरक्षित है? क्या कंपाइलर हमेशा सही (हालांकि धीमा) कोड को पैक किए गए स्ट्रक्चर्स के गलत सदस्यों तक पहुंचने के लिए उत्पन्न करता है? क्या सभी मामलों में ऐसा करना संभव है?


1
Gcc बग रिपोर्ट को अब पॉइंटर असाइनमेंट पर चेतावनी के अलावा (और चेतावनी को निष्क्रिय करने का विकल्प) के रूप में चिह्नित किया गया है। मेरे उत्तर में विवरण ।
कीथ थॉम्पसन

जवाबों:


148

हां, __attribute__((packed))कुछ प्रणालियों पर संभावित रूप से असुरक्षित है। लक्षण शायद x86 पर दिखाई नहीं देगा, जो समस्या को और अधिक कपटी बनाता है; x86 सिस्टम पर परीक्षण समस्या को प्रकट नहीं करेगा। (X86 पर, गलत तरीके से एक्सेस को हार्डवेयर में संभाला जाता है; यदि आप एक int*पॉइंटर को डिसेंट करते हैं जो एक अजीब पते की ओर इशारा करता है, तो यह थोड़ा धीमा होगा अगर यह ठीक से गठबंधन किया गया था, लेकिन आपको सही परिणाम मिलेगा।)

कुछ अन्य प्रणालियों पर, जैसे कि SPARC, एक गलत intवस्तु तक पहुँचने का प्रयास एक बस त्रुटि का कारण बनता है, जिससे प्रोग्राम क्रैश हो जाता है।

ऐसी प्रणालियाँ भी आई हैं, जहाँ गलत तरीके से पहुंच पता चुपचाप पते के कम-क्रम बिट्स को अनदेखा कर देती है, जिससे यह मेमोरी के गलत भाग तक पहुँच सकती है।

निम्नलिखित कार्यक्रम पर विचार करें:

#include <stdio.h>
#include <stddef.h>
int main(void)
{
    struct foo {
        char c;
        int x;
    } __attribute__((packed));
    struct foo arr[2] = { { 'a', 10 }, {'b', 20 } };
    int *p0 = &arr[0].x;
    int *p1 = &arr[1].x;
    printf("sizeof(struct foo)      = %d\n", (int)sizeof(struct foo));
    printf("offsetof(struct foo, c) = %d\n", (int)offsetof(struct foo, c));
    printf("offsetof(struct foo, x) = %d\n", (int)offsetof(struct foo, x));
    printf("arr[0].x = %d\n", arr[0].x);
    printf("arr[1].x = %d\n", arr[1].x);
    printf("p0 = %p\n", (void*)p0);
    printf("p1 = %p\n", (void*)p1);
    printf("*p0 = %d\n", *p0);
    printf("*p1 = %d\n", *p1);
    return 0;
}

Gcc 4.5.2 के साथ x86 उबंटू पर, यह निम्नलिखित आउटपुट का उत्पादन करता है:

sizeof(struct foo)      = 5
offsetof(struct foo, c) = 0
offsetof(struct foo, x) = 1
arr[0].x = 10
arr[1].x = 20
p0 = 0xbffc104f
p1 = 0xbffc1054
*p0 = 10
*p1 = 20

SPARC Solaris 9 पर gcc 4.5.1 के साथ, यह निम्नलिखित उत्पादन करता है:

sizeof(struct foo)      = 5
offsetof(struct foo, c) = 0
offsetof(struct foo, x) = 1
arr[0].x = 10
arr[1].x = 20
p0 = ffbff317
p1 = ffbff31c
Bus error

दोनों ही मामलों में, इस कार्यक्रम को बिना किसी अतिरिक्त विकल्प के संकलित किया गया है gcc packed.c -o packed

(एक प्रोग्राम जो सरणी के बजाय एकल संरचना का उपयोग करता है, समस्या को मज़बूती से प्रदर्शित नहीं करता है, क्योंकि कंपाइलर एक विषम पते पर संरचना को आवंटित कर सकता है ताकि xसदस्य ठीक से गठबंधन हो। दो struct fooवस्तुओं की एक सरणी के साथ , कम से कम एक या दूसरे। एक गलत xसदस्य होगा।)

(इस मामले में, p0एक गलत पते की ओर इशारा करता है, क्योंकि यह एक intसदस्य के बाद एक पैक किए गए सदस्य को इंगित करता है charp1सही ढंग से गठबंधन करने के लिए होता है, क्योंकि यह सरणी के दूसरे तत्व में एक ही सदस्य को इंगित करता है, इसलिए charइससे पहले दो ऑब्जेक्ट हैं। - और स्पार्क सोलारिस पर सरणी arrको एक पते पर आवंटित किया गया प्रतीत होता है जो समान है, लेकिन 4. का एक से अधिक नहीं है।)

जब xकिसी सदस्य के struct fooनाम का जिक्र किया जाता है, तो संकलक जानता है कि xसंभावित रूप से गलत संकेत दिया गया है, और इसे सही तरीके से एक्सेस करने के लिए अतिरिक्त कोड उत्पन्न करेगा।

एक बार जब पता arr[0].xया arr[1].xएक पॉइंटर ऑब्जेक्ट में संग्रहीत किया गया है, तो न तो संकलक और न ही चल रहे कार्यक्रम को पता है कि यह एक गलत intऑब्जेक्ट को इंगित करता है । यह सिर्फ यह मानता है कि यह ठीक से संरेखित है, जिसके परिणामस्वरूप (कुछ प्रणालियों पर) बस त्रुटि या इसी तरह की अन्य विफलता है।

इसे gcc में फिक्स करना, मेरा मानना ​​है कि अव्यावहारिक है। एक सामान्य समाधान के लिए, गैर-तुच्छ संरेखण आवश्यकताओं के साथ किसी भी प्रकार के लिए एक पॉइंटर को रोकने के लिए प्रत्येक प्रयास की आवश्यकता होगी (क) संकलन समय पर यह साबित करना कि पॉइंटर एक भरे हुए संरचना के गलत सदस्य को इंगित नहीं करता है, या (बी) बल्कियर और धीमे कोड उत्पन्न करना जो संरेखित या गलत वस्तुओं को संभाल सकता है।

मैंने एक gcc बग रिपोर्ट प्रस्तुत की है । जैसा कि मैंने कहा, मुझे विश्वास नहीं है कि इसे ठीक करना व्यावहारिक है, लेकिन प्रलेखन को इसका उल्लेख करना चाहिए (यह वर्तमान में नहीं है)।

अद्यतन : 2018-12-20 के रूप में, यह बग FIXED के रूप में चिह्नित है। पैच -Waddress-of-packed-memberडिफ़ॉल्ट रूप से सक्षम एक नए विकल्प के अलावा के साथ gcc 9 में दिखाई देगा ।

जब स्ट्रक्चर या यूनियन के पैक्ड सदस्य का पता लिया जाता है, तो इसका परिणाम अनलॉग्ड पॉइंटर मान हो सकता है। यह पैच जोड़ता है -Waddress-of-पैक-मेंबर को पॉइंटर असाइनमेंट पर अलाइनमेंट की जाँच करने के लिए और अन-असाइन किए गए प्वॉइंट के साथ-साथ अनलॉग्ड पाइंटर को चेतावनी देने के लिए।

मैं सिर्फ स्रोत से जीसीसी के उस संस्करण का निर्माण किया है। उपरोक्त कार्यक्रम के लिए, यह इन निदानों का उत्पादन करता है:

c.c: In function main’:
c.c:10:15: warning: taking address of packed member of struct foo may result in an unaligned pointer value [-Waddress-of-packed-member]
   10 |     int *p0 = &arr[0].x;
      |               ^~~~~~~~~
c.c:11:15: warning: taking address of packed member of struct foo may result in an unaligned pointer value [-Waddress-of-packed-member]
   11 |     int *p1 = &arr[1].x;
      |               ^~~~~~~~~

1
संभावित रूप से भ्रमित है, और उत्पन्न करेगा ... क्या?
आलमो डिक

5
एआरएम पर गलत तरीके से तैयार किए गए संरचनात्मक तत्व अजीब चीजें करते हैं: कुछ पहुंच दोष पैदा करते हैं, अन्य पुनर्प्राप्त डेटा को काउंटर-सहज रूप से पुनर्व्यवस्थित करने या आसन्न अप्रत्याशित डेटा को शामिल करने का कारण बनते हैं।
wallyk

8
ऐसा लगता है कि पैकिंग स्वयं सुरक्षित है, लेकिन पैक्ड सदस्यों का उपयोग कैसे किया जाता है यह असुरक्षित हो सकता है। पुराने एआरएम-आधारित सीपीयू ने अनलग्ड मेमोरी एक्सेस का समर्थन नहीं किया, नए संस्करण करते हैं, लेकिन मुझे पता है कि सिम्बियन ओएस अभी भी इन नए संस्करणों (समर्थन बंद हो गया है) पर चलने पर अन-असाइन किए गए एक्सेस को बंद कर देता है।
जेम्स

14
Gcc के भीतर इसे ठीक करने का एक और तरीका होगा कि टाइप सिस्टम का उपयोग किया जाए: इसके लिए आवश्यक है कि पैक्ड स्ट्रक्चर्स के सदस्यों को पॉइंटर्स केवल उन पॉइंटर्स को सौंपे जा सकते हैं जो खुद को पैक्ड के रूप में चिह्नित करते हैं (यानी संभावित अनलग्ड)। लेकिन वास्तव में: पैक किए गए ढांचे, बस कहते हैं कि नहीं।
कैफ़े

9
@ फैलीवियस: मेरा मुख्य उद्देश्य वहाँ की जानकारी प्राप्त करना था। Meta.stackexchange.com/questions/17463/… पर
कीथ थॉम्पसन

62

जैसा कि ऊपर कहा गया है, कि पैक की गई संरचना के सदस्य को पॉइंटर न लें। यह बस आग से खेल रहा है। जब आप कहते हैं __attribute__((__packed__))या #pragma pack(1), आप वास्तव में क्या कह रहे हैं "अरे जीसीसी, मैं वास्तव में जानता हूं कि मैं क्या कर रहा हूं।" जब यह पता चलता है कि आप नहीं करते हैं, तो आप संकलक को ठीक से दोष नहीं दे सकते।

हालांकि हम कंपाइलर को इसके लिए शालीनता का दोषी ठहरा सकते हैं। जीसीसी एक है जबकि -Wcast-alignविकल्प, यह डिफ़ॉल्ट रूप से और न ही साथ सक्षम नहीं है -Wallया -Wextra। यह जाहिरा तौर पर जीसीसी डेवलपर्स के कारण इस प्रकार के कोड को मस्तिष्क-मृत " घृणा " को संबोधित करने के योग्य मानते हैं - समझने योग्य तिरस्कार।

निम्नलिखित को धयान मे रखते हुए:

struct  __attribute__((__packed__)) my_struct {
    char c;
    int i;
};

struct my_struct a = {'a', 123};
struct my_struct *b = &a;
int c = a.i;
int d = b->i;
int *e __attribute__((aligned(1))) = &a.i;
int *f = &a.i;

यहाँ, एक प्रकार का aपैक्ड स्ट्रक्चर है (जैसा कि ऊपर परिभाषित किया गया है)। इसी तरह, bएक पैक्ड संरचना के लिए एक सूचक है। अभिव्यक्ति a.iका प्रकार (मूल रूप से) 1 बाइट संरेखण के साथ एक int l-value हैcऔर dदोनों सामान्य हैं int। पढ़ते समय a.i, कंपाइलर बिना असाइन किए गए एक्सेस के लिए कोड जनरेट करता है। जब आप पढ़ते हैं b->i, तब bभी पता चलता है कि यह पैक है, इसलिए कोई समस्या नहीं है। eएक-बाइट-संरेखित int के लिए एक सूचक है, इसलिए संकलक जानता है कि कैसे सही रूप से और साथ ही डीफ़ेरेन्स करना है। लेकिन जब आप असाइनमेंट बनाते f = &a.iहैं, तो आप एक असंबद्ध इंट पॉइंटर के मान को संरेखित इंट पॉइंटर चर में स्टोर कर रहे हैं - यही वह जगह है जहाँ आप गलत हो गए। और मैं मानता हूं, जीसीसी को इस चेतावनी को सक्षम होना चाहिएडिफ़ॉल्ट (यहां तक कि में नहीं -Wallया -Wextra)।


6
+1 यह बताने के लिए कि अनलॉन्ग किए गए स्ट्रक्चर्स के साथ पॉइंटर्स का उपयोग कैसे करें!
सौम्या

@ सौम्या अंक के लिए धन्यवाद! :) लेकिन ध्यान रखें कि __attribute__((aligned(1)))यह एक gcc एक्सटेंशन है और पोर्टेबल नहीं है। मेरे ज्ञान के लिए, सी में अनलॉग्टेड एक्सेस (किसी भी कंपाइलर / हार्डवेयर संयोजन के साथ) करने का एकमात्र पोर्टेबल तरीका बाइट-वार मेमोरी कॉपी (मेमसीपी या समान) के साथ है। कुछ हार्डवेयर में बिना असाइन किए गए एक्सेस के निर्देश भी नहीं होते हैं। मेरी विशेषज्ञता हाथ और x86 के साथ है, जो दोनों कर सकती है, हालांकि अनलगिनेट एक्सेस धीमा है। इसलिए यदि आपको कभी भी उच्च प्रदर्शन के साथ ऐसा करने की आवश्यकता है, तो आपको हार्डवेयर को सूँघने और आर्च-विशिष्ट चाल का उपयोग करने की आवश्यकता होगी।
डैनियल सैंटोस

4
@ सौम्या दुख की बात है, __attribute__((aligned(x)))अब नजरअंदाज किया जाता है जब संकेत के लिए उपयोग किया जाता है। :( मुझे अभी तक इसका पूरा ब्योरा नहीं है, लेकिन __builtin_assume_aligned(ptr, align)सही कोड उत्पन्न करने के लिए जीसीसी का उपयोग करना प्रतीत होता है। जब मैं अधिक संक्षिप्त उत्तर देता हूं (और उम्मीद है कि एक बग रिपोर्ट) मैं अपना जवाब अपडेट करूंगा।
डैनियल सैंटोस

@ डैनियलसेंटोस: एक गुणवत्ता संकलक जिसका मैं उपयोग करता हूं (कीइल) पॉइंटर्स के लिए "पैक" क्वालीफायर को पहचानता है; यदि एक संरचना को "पैक" घोषित किया जाता है, तो एक uint32_tसदस्य का पता लेने से उपज होगी uint32_t packed*; ऐसे पॉइंटर से पढ़ने की कोशिश करना जैसे कि एक कोर्टेक्स- M0 IIRC एक सबरूटीन कहेगा जो ~ 7x तब तक लेगा जब तक कि एक सामान्य रीड अगर पॉइंटर अनलगनेटेड है या ~ 3x जब तक यह एलाइन हो जाता है, लेकिन किसी भी स्थिति में अनुमानित व्यवहार करेगा [इन-लाइन कोड में 5x का समय लगेगा चाहे वह संरेखित हो या अ-असाइन किया गया हो]।
सुपरकैट


49

यह तब तक पूरी तरह से सुरक्षित है जब तक आप हमेशा .(डॉट) या ->अंकन के माध्यम से संरचना के माध्यम से मूल्यों तक पहुंचते हैं।

जो सुरक्षित नहीं है वह बिना डेटा के सूचक को ले जा रहा है और फिर उस खाते में ले जाए बिना इसे एक्सेस कर रहा है।

इसके अलावा, भले ही संरचना में प्रत्येक आइटम को अलंकृत होने के लिए जाना जाता है, यह एक विशेष तरीके से अलिखित होने के लिए जाना जाता है , इसलिए समग्र रूप में संरचना को संकलक की उम्मीद के रूप में गठबंधन किया जाना चाहिए या परेशानी होगी (कुछ प्लेटफार्मों पर, या भविष्य में अगर एक नया तरीका अविशिष्ट पहुँच का अनुकूलन करने के लिए आविष्कार किया गया है)।


हम्म, मुझे आश्चर्य है कि क्या होता है यदि आप एक पैक की गई संरचना को एक और पैक किए गए ढांचे के अंदर रखते हैं जहां संरेखण अलग होगा? दिलचस्प सवाल है, लेकिन यह जवाब नहीं बदलना चाहिए।
ams

GCC हमेशा संरचना को या तो संरेखित नहीं करेगा। उदाहरण के लिए: संरचनात्मक फू {इंट एक्स; चार सी; } __attribute __ ((पैक)); संरचना बार {चार सी; संरचना foo f; }; मैंने पाया कि बार :: f :: x जरूरी नहीं कि गठबंधन किया जाए, कम से कम MIPS के कुछ स्वादों पर।
एंटोन

3
: आपको केवल पठनीयता के लिए अतिरिक्त नाम के साथ फ़ील्ड की एक समतल श्रृंखला के रूप में एक संरचना की कल्पना करनी चाहिए।
आमस

6

इस विशेषता का उपयोग करना निश्चित रूप से असुरक्षित है।

एक ख़ास बात यह है कि यह टूटने की क्षमता है unionजिसमें एक सदस्य को लिखने के लिए दो या दो से अधिक संरचनाएं होती हैं और दूसरे को पढ़ती है यदि संरचना में सदस्यों का एक सामान्य प्रारंभिक क्रम होता है। C11 मानक राज्यों की धारा 6.5.2.3 :

6 यूनियनों के उपयोग को सरल बनाने के लिए एक विशेष गारंटी दी जाती है: यदि किसी संघ में कई संरचनाएँ होती हैं जो एक सामान्य प्रारंभिक अनुक्रम को साझा करती हैं (नीचे देखें), और यदि वर्तमान में यूनियन ऑब्जेक्ट में इनमें से एक संरचना शामिल है, तो इसका निरीक्षण करने की अनुमति है कहीं भी उनमें से किसी का भी प्रारंभिक प्रारंभिक भाग जो कि संघ के पूर्ण प्रकार की घोषणा है, दिखाई देता है। यदि किसी सदस्य के पास एक या अधिक प्रारंभिक सदस्यों के अनुक्रम के लिए संगत प्रकार (और बिट-फ़ील्ड के लिए समान चौड़ाई) हों, तो ओ ओ स्ट्रक्चर्स एक सामान्य प्रारंभिक अनुक्रम साझा करते हैं।

...

9 उदाहरण 3 निम्नलिखित एक मान्य टुकड़ा है:

union {
    struct {
        int    alltypes;
    }n;
    struct {
        int    type;
        int    intnode;
    } ni;
    struct {
        int    type;
        double doublenode;
    } nf;
}u;
u.nf.type = 1;
u.nf.doublenode = 3.14;
/*
...
*/
if (u.n.alltypes == 1)
if (sin(u.nf.doublenode) == 0.0)
/*
...
*/

जब __attribute__((packed))पेश किया जाता है तो यह टूट जाता है। निम्नलिखित उदाहरण Ubuntu 16.04 x64 पर चलाए गए थे जिसमें अनुकूलन के साथ gcc 5.4.0 का उपयोग किया गया था:

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

struct s1
{
    short a;
    int b;
} __attribute__((packed));

struct s2
{
    short a;
    int b;
};

union su {
    struct s1 x;
    struct s2 y;
};

int main()
{
    union su s;
    s.x.a = 0x1234;
    s.x.b = 0x56789abc;

    printf("sizeof s1 = %zu, sizeof s2 = %zu\n", sizeof(struct s1), sizeof(struct s2));
    printf("s.y.a=%hx, s.y.b=%x\n", s.y.a, s.y.b);
    return 0;
}

आउटपुट:

sizeof s1 = 6, sizeof s2 = 8
s.y.a=1234, s.y.b=5678

भले ही struct s1और struct s2एक "सामान्य प्रारंभिक अनुक्रम" हो, पूर्व के लिए लागू पैकिंग का मतलब है कि संबंधित सदस्य एक ही बाइट ऑफसेट पर नहीं रहते हैं। परिणाम यह है कि सदस्य x.bको लिखा गया मूल्य सदस्य से पढ़े गए मूल्य के समान नहीं है y.b, भले ही मानक कहता है कि उन्हें समान होना चाहिए।


कोई यह तर्क दे सकता है कि यदि आप किसी एक संरचना को पैक करते हैं और दूसरे को नहीं, तो आप उनसे लगातार लेआउट की अपेक्षा नहीं करेंगे। लेकिन हां, यह एक और मानक आवश्यकता है कि इसका उल्लंघन हो सकता है।
कीथ थॉम्पसन

1

(निम्नलिखित चित्रण करने के लिए पकाया गया एक बहुत ही कृत्रिम उदाहरण है।) पैक्ड स्ट्रक्चर्स का एक प्रमुख उपयोग वह जगह है जहां आपके पास डेटा की एक धारा है (256 बाइट्स कहें) जिसमें आप अर्थ की आपूर्ति करना चाहते हैं। यदि मैं एक छोटा सा उदाहरण लेता हूं, तो मान लीजिए कि मेरा अरुडिनो पर चलने वाला एक कार्यक्रम है, जो सीरियल के माध्यम से 16 बाइट्स का पैकेट भेजता है, जिसका निम्न अर्थ है:

0: message type (1 byte)
1: target address, MSB
2: target address, LSB
3: data (chars)
...
F: checksum (1 byte)

तब मैं ऐसा कुछ घोषित कर सकता हूं

typedef struct {
  uint8_t msgType;
  uint16_t targetAddr; // may have to bswap
  uint8_t data[12];
  uint8_t checksum;
} __attribute__((packed)) myStruct;

और फिर मैं सूचक अंकगणितीय के साथ फ़िडलिंग के बजाय aStruct.targetAddr के माध्यम से targetAddr बाइट्स का उल्लेख कर सकता हूं।

अब संरेखण सामान होने के साथ, प्राप्त डेटा में मेमोरी में एक शून्य * पॉइंटर लेना और इसे myStruct पर कास्टिंग करना * तब तक काम नहीं करेगा जब तक कंपाइलर संरचना को पैक के रूप में व्यवहार नहीं करता (अर्थात, यह निर्दिष्ट क्रम में डेटा संग्रहीत करता है और 16 का उपयोग करता है इस उदाहरण के लिए बाइट्स)। अनलग्ड रीड्स के लिए प्रदर्शन दंड हैं, इसलिए आपके प्रोग्राम को सक्रिय रूप से काम करने वाले डेटा के लिए पैक किए गए स्ट्रक्चर्स का उपयोग करना आवश्यक नहीं है एक अच्छा विचार है। लेकिन जब आपके प्रोग्राम को बाइट्स की सूची के साथ आपूर्ति की जाती है, तो पैक्ड संरचनाएं उन कार्यक्रमों को लिखना आसान बनाती हैं जो सामग्री तक पहुंचते हैं।

अन्यथा आप C ++ का उपयोग करते हुए और एक्सेसर विधियों और सामानों के साथ एक वर्ग लिख रहे हैं जो कि पर्दे के पीछे सूचक अंकगणित करता है। संक्षेप में, पैक्ड संरचनाएं पैक किए गए डेटा के साथ कुशलता से निपटने के लिए हैं, और पैक्ड डेटा वह हो सकता है जो आपके प्रोग्राम के साथ काम करने के लिए दिया गया हो। अधिकांश भाग के लिए, आपको कोड को संरचना से बाहर के मूल्यों को पढ़ना चाहिए, उनके साथ काम करना चाहिए और जब किया जाता है तो उन्हें वापस लिखना चाहिए। बाकी सभी को पैक किए गए ढांचे के बाहर किया जाना चाहिए। समस्या का एक हिस्सा निम्न स्तर का सामान है जो C प्रोग्रामर से छिपाने की कोशिश करता है, और घेरा कूदने की आवश्यकता होती है यदि ऐसी चीजें वास्तव में प्रोग्रामर के लिए मायने रखती हैं। (आपको भाषा में लगभग एक अलग 'डेटा लेआउट' निर्माण की आवश्यकता है ताकि आप कह सकें 'यह बात 48 बाइट्स लंबी है, फू 13 बाइट्स में डेटा को संदर्भित करता है, और इस प्रकार व्याख्या की जानी चाहिए', और एक अलग संरचित डेटा निर्माण;


जब तक मैं कुछ याद कर रहा हूँ, इस सवाल का जवाब नहीं है। आप तर्क देते हैं कि संरचना पैकिंग सुविधाजनक है (जो यह है), लेकिन आप इस सवाल का समाधान नहीं करते हैं कि क्या यह सुरक्षित है। इसके अलावा, आप उस प्रदर्शन को दंडित करते हैं जो बिना पढ़े लिखे के लिए दंडित करता है; यह x86 के लिए सही है, लेकिन सभी प्रणालियों के लिए नहीं, जैसा कि मैंने अपने उत्तर में प्रदर्शित किया है।
कीथ थॉम्पसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.