केवल मानक पुस्तकालय का उपयोग करके संरेखित मेमोरी कैसे आवंटित करें?


421

मैंने अभी-अभी एक नौकरी साक्षात्कार के भाग के रूप में एक परीक्षा समाप्त की, और एक प्रश्न ने मुझे रोक दिया, यहां तक ​​कि संदर्भ के लिए Google का उपयोग भी किया। मैं यह देखना चाहूंगा कि स्टैकऑवरफ्लो क्रू इसके साथ क्या कर सकता है:

memset_16alignedफ़ंक्शन को इसके पास दिए गए 16-बाइट संरेखित पॉइंटर की आवश्यकता होती है, या यह क्रैश हो जाएगा।

a) आप 1024 बाइट्स स्मृति को कैसे आवंटित करेंगे, और इसे 16 बाइट की सीमा में संरेखित करेंगे?
बी) memset_16alignedनिष्पादित होने के बाद मेमोरी को मुक्त करें ।

{    
   void *mem;
   void *ptr;

   // answer a) here

   memset_16aligned(ptr, 0, 1024);

   // answer b) here    
}

89
हम्म ... लंबे समय तक कोड व्यवहार्यता के लिए, "आग किसने भी लिखी है जिसने memset_16align लिखा है और इसे ठीक करें या इसे बदल दें ताकि इसकी एक अजीब सीमा की स्थिति न हो"
स्टीवन ए। लोवे

29
निश्चित रूप से पूछने के लिए एक वैध प्रश्न - "अजीब स्मृति संरेखण क्यों"। लेकिन इसके अच्छे कारण हो सकते हैं - इस मामले में, यह हो सकता है कि memset_16aligned () 128-बिट पूर्णांक का उपयोग कर सकता है और यह आसान है अगर स्मृति को संरेखित करने के लिए जाना जाता है। आदि
जोनाथन लेफ़लर

5
जिसने भी लिखा है वह आंतरिक लूप को साफ करने के लिए आंतरिक 16-बाइट संरेखण का उपयोग कर सकता है और गैर-संरेखित सिरों को साफ करने के लिए एक छोटा डेटा प्रोलॉग / एपिलॉग। कोडर्स को अतिरिक्त मेमोरी पॉइंट हैंडल करने की तुलना में यह बहुत आसान होगा।
अदिसक

8
कोई व्यक्ति 16 बाइट सीमा से जुड़ा डेटा क्यों चाहेगा? शायद इसे 128 बिट एसएसई रजिस्टर में लोड करना है। मेरा मानना ​​है कि नए (नए) अनलॉग्ड मूव्स (जैसे, मूव्ड, lddqu) धीमे हैं, या शायद वे SSE2 / 3 के बिना प्रोसेसर को लक्षित कर रहे हैं

11
पते को संरेखित करने से कैश के अनुकूलित उपयोग के साथ-साथ कैश और रैम के विभिन्न स्तरों (अधिकांश सामान्य वर्कलोड के लिए) के बीच उच्च बैंडविड्थ की ओर जाता है। यहाँ देखें stackoverflow.com/questions/381244/purpose-of-memory-alignment
रात 13'13 बजे दीपदान

जवाबों:


585

मूल उत्तर

{
    void *mem = malloc(1024+16);
    void *ptr = ((char *)mem+16) & ~ 0x0F;
    memset_16aligned(ptr, 0, 1024);
    free(mem);
}

निश्चित उत्तर

{
    void *mem = malloc(1024+15);
    void *ptr = ((uintptr_t)mem+15) & ~ (uintptr_t)0x0F;
    memset_16aligned(ptr, 0, 1024);
    free(mem);
}

अनुरोध के अनुसार स्पष्टीकरण

पहला कदम पर्याप्त खाली स्थान आवंटित करना है, बस मामले में। चूंकि मेमोरी 16-बाइट संरेखित होनी चाहिए (इसका अर्थ है कि प्रमुख बाइट पते को 16 के एक से अधिक होना चाहिए), 16 अतिरिक्त बाइट्स को जोड़ना यह गारंटी देता है कि हमारे पास पर्याप्त जगह है। कहीं पहले 16 बाइट्स में, 16-बाइट संरेखित सूचक है। (ध्यान दें कि malloc()एक सूचक है कि पर्याप्त रूप से अच्छी तरह से करने के लिए गठबंधन किया है वापस करने के लिए माना जाता है किसी भी । प्रयोजन हालांकि, 'कोई भी' का अर्थ बुनियादी प्रकार जैसी चीजों के लिए मुख्य रूप से है - long, double, long double, long long।, और कार्यों के लिए वस्तुओं के लिए संकेत और संकेत जब आप कर रहे हैं अधिक विशिष्ट चीजें करना, जैसे ग्राफिक्स सिस्टम के साथ खेलना, उन्हें बाकी सिस्टम की तुलना में अधिक कठोर संरेखण की आवश्यकता हो सकती है - इसलिए इस तरह के सवाल और जवाब।)

अगला कदम शून्य पॉइंटर को एक चर पॉइंटर में बदलना है; जीसीसी के बावजूद, आप शून्य बिंदुओं पर सूचक अंकगणित करने के लिए नहीं हैं (और जीसीसी के पास आपके दुरुपयोग करने पर आपको बताने के लिए चेतावनी विकल्प हैं)। फिर स्टार्ट पॉइंटर में 16 जोड़ दें। मान लीजिए कि malloc()आपने एक बुरी तरह से संरेखित सूचक को लौटा दिया: 0x800001। 16 जोड़ने पर 0x800011 मिलता है। अब मैं 16-बाइट सीमा तक नीचे जाना चाहता हूं - इसलिए मैं अंतिम 4 बिट्स को रीसेट करना चाहता हूं। 0x0F में अंतिम 4 बिट्स एक पर सेट है; इसलिए, ~0x0Fसभी बिट्स को अंतिम चार को छोड़कर एक सेट किया गया है। एंडिंग कि 0x800011 के साथ 0x800010 देता है। आप अन्य संतानों पर पुनरावृति कर सकते हैं और देख सकते हैं कि वही अंकगणित काम करता है।

अंतिम चरण, free()आसान है: आप हमेशा, और केवल, free()एक ऐसे मूल्य पर लौटें, जिसमें से एक malloc(), calloc()या आपके पास realloc()लौटा - और कुछ भी एक आपदा है। आपने memउस मूल्य को रखने के लिए सही तरीके से प्रदान किया - धन्यवाद। मुक्त इसे जारी करता है।

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

किसी और posix_memalign()को संरेखित स्मृति प्राप्त करने का एक और तरीका बताया गया है; यह हर जगह उपलब्ध नहीं है, लेकिन अक्सर इसे आधार के रूप में उपयोग किया जा सकता है। ध्यान दें कि यह सुविधाजनक था कि संरेखण 2 की शक्ति थी; अन्य संरेखण गड़बड़ हैं।

एक और टिप्पणी - यह कोड यह जांच नहीं करता है कि आवंटन सफल हुआ।

संशोधन

विंडोज प्रोग्रामर ने बताया कि आप पॉइंटर्स पर बिट मास्क ऑपरेशन नहीं कर सकते हैं, और वास्तव में, जीसीसी (3.4.6 और 4.3.1 परीक्षण) इस तरह की शिकायत नहीं करता है। तो, मूल कोड का एक संशोधित संस्करण - मुख्य कार्यक्रम में परिवर्तित हो जाता है, इस प्रकार है। मैंने 16 के बजाय सिर्फ 15 को जोड़ने की स्वतंत्रता ली है, जैसा कि बताया गया है। मैं उपयोग कर रहा हूँ uintptr_tक्योंकि C99 सबसे प्लेटफार्मों पर सुलभ होने के लिए काफी लंबा हो गया है। यदि यह के इस्तेमाल के लिए नहीं था PRIXPTRमें printf()बयान, यह करने के लिए पर्याप्त होगा #include <stdint.h>का उपयोग कर के बजाय #include <inttypes.h>[इस कोड में CR द्वारा इंगित किया गया फिक्स शामिल है , जो कई साल पहले बिल के द्वारा बनाए गए एक बिंदु को दोहरा रहा था, जिसे मैं अब तक अनदेखा करने में कामयाब रहा था।]

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

static void memset_16aligned(void *space, char byte, size_t nbytes)
{
    assert((nbytes & 0x0F) == 0);
    assert(((uintptr_t)space & 0x0F) == 0);
    memset(space, byte, nbytes);  // Not a custom implementation of memset()
}

int main(void)
{
    void *mem = malloc(1024+15);
    void *ptr = (void *)(((uintptr_t)mem+15) & ~ (uintptr_t)0x0F);
    printf("0x%08" PRIXPTR ", 0x%08" PRIXPTR "\n", (uintptr_t)mem, (uintptr_t)ptr);
    memset_16aligned(ptr, 0, 1024);
    free(mem);
    return(0);
}

और यहाँ एक मामूली रूप से अधिक सामान्यीकृत संस्करण है, जो उन आकारों के लिए काम करेगा जो 2 की शक्ति हैं:

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

static void memset_16aligned(void *space, char byte, size_t nbytes)
{
    assert((nbytes & 0x0F) == 0);
    assert(((uintptr_t)space & 0x0F) == 0);
    memset(space, byte, nbytes);  // Not a custom implementation of memset()
}

static void test_mask(size_t align)
{
    uintptr_t mask = ~(uintptr_t)(align - 1);
    void *mem = malloc(1024+align-1);
    void *ptr = (void *)(((uintptr_t)mem+align-1) & mask);
    assert((align & (align - 1)) == 0);
    printf("0x%08" PRIXPTR ", 0x%08" PRIXPTR "\n", (uintptr_t)mem, (uintptr_t)ptr);
    memset_16aligned(ptr, 0, 1024);
    free(mem);
}

int main(void)
{
    test_mask(16);
    test_mask(32);
    test_mask(64);
    test_mask(128);
    return(0);
}

test_mask()एक सामान्य उद्देश्य आवंटन फ़ंक्शन में परिवर्तित करने के लिए , आवंटनकर्ता से एकल वापसी मूल्य को रिलीज़ पते को एनकोड करना होगा, जैसा कि कई लोगों ने अपने उत्तरों में संकेत दिया है।

साक्षात्कारकर्ताओं के साथ समस्या

उरी ने टिप्पणी की: हो सकता है कि मैं आज सुबह [एक] पढ़ने की समस्या को समझ रहा हूं, लेकिन अगर साक्षात्कार प्रश्न विशेष रूप से कहता है: "आप 1024 बाइट्स मेमोरी कैसे आवंटित करेंगे" और आप स्पष्ट रूप से इससे अधिक आवंटित करते हैं। कि साक्षात्कारकर्ता से एक स्वचालित विफलता नहीं होगी?

मेरी प्रतिक्रिया 300-चरित्र की टिप्पणी में फिट नहीं होगी ...

यह निर्भर करता है, मुझे लगता है। मुझे लगता है कि अधिकांश लोग (मेरे सहित) ने सवाल उठाया कि "आप एक स्थान कैसे आवंटित करेंगे जिसमें 1024 बाइट्स डेटा संग्रहीत किया जा सकता है, और जहां आधार पता 16 बाइट्स का एक बहु है"। यदि साक्षात्कारकर्ता का वास्तव में मतलब है कि आप 1024 बाइट्स (केवल) कैसे आवंटित कर सकते हैं और इसमें 16-बाइट संरेखित हैं, तो विकल्प अधिक सीमित हैं।

  • स्पष्ट रूप से, एक संभावना 1024 बाइट्स आवंटित करने की है और फिर उस पते को 'संरेखण उपचार' देना है; उस दृष्टिकोण के साथ समस्या यह है कि वास्तविक उपलब्ध स्थान ठीक से निर्धारित नहीं है (प्रयोग करने योग्य स्थान 1008 और 1024 बाइट्स के बीच है, लेकिन इसमें कौन सा आकार निर्दिष्ट करने के लिए एक तंत्र उपलब्ध नहीं था), जो इसे उपयोगी से कम प्रदान करता है।
  • एक और संभावना यह है कि आपसे एक पूर्ण मेमोरी एलोकेटर लिखने और यह सुनिश्चित करने की अपेक्षा की जाती है कि आपके द्वारा लौटाए गए 1024-बाइट ब्लॉक उचित रूप से संरेखित हों। यदि ऐसा है, तो आप संभवतः प्रस्तावित समाधान के समान एक ऑपरेशन कर रहे हैं, लेकिन आप इसे आवंटनकर्ता के अंदर छिपाते हैं।

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

दुनिया चलती है

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

C11 (आईएसओ / आईईसी 9899: 2011) जोड़ा समारोह aligned_alloc():

7.22.3.1 aligned_allocफ़ंक्शन

सार

#include <stdlib.h>
void *aligned_alloc(size_t alignment, size_t size);

विवरण एक वस्तु जिसका संरेखण द्वारा निर्दिष्ट किया जाता के लिए समारोह आवंटित अंतरिक्ष , जिसका आकार द्वारा निर्दिष्ट किया जाता है, और जिसका मूल्य अनिश्चित है। लागू करने के लिए समर्थित मूल्य का एक मान्य संरेखण होना चाहिए और इसका मूल्य एक से अधिक होना चाहिए ।
aligned_allocalignmentsizealignmentsizealignment

रिटर्न समारोह रिटर्न या तो एक नल पॉइंटर या आबंटित स्थान के लिए सूचक।
aligned_alloc

और POSIX परिभाषित करता है posix_memalign():

#include <stdlib.h>

int posix_memalign(void **memptr, size_t alignment, size_t size);

विवरण

posix_memalign()समारोह का आवंटन करेगा sizeएक सीमा द्वारा निर्दिष्ट पर गठबंधन बाइट्स alignment, और में आबंटित स्मृति के लिए सूचक लौटा देगा memptr। का मान alignmentदो की एक शक्ति होगी sizeof(void *)

सफल समापन पर, द्वारा इंगित किया गया मान memptrएक से अधिक होगा alignment

यदि अनुरोधित स्थान का आकार 0 है, तो व्यवहार कार्यान्वयन-परिभाषित है; मूल्य वापस आ memptrजाएगा या तो एक शून्य सूचक या एक अद्वितीय सूचक होगा।

free()समारोह स्मृति है कि पहले से आबंटित की गई है पुनःआवंटन जाएगा posix_memalign()

प्रतिलाभ की मात्रा

सफल होने पर, posix_memalign()शून्य वापस आ जाएगा; अन्यथा, त्रुटि दर्शाने के लिए एक त्रुटि संख्या वापस आ जाएगी।

प्रश्न का उत्तर देने के लिए या तो इन दोनों का उपयोग किया जा सकता है, लेकिन मूल रूप से प्रश्न का उत्तर दिए जाने पर केवल POSIX फ़ंक्शन एक विकल्प था।

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


13
और मैं C ++ के साथ जंग खा रहा हूं, लेकिन मुझे वास्तव में भरोसा नहीं है कि ~ 0x0F पॉइंटर के आकार का ठीक से विस्तार करेगा। यदि ऐसा नहीं होता है, तो सभी नर्क ढीले हो जाएंगे क्योंकि आप अपने पॉइंटर के सबसे महत्वपूर्ण बिट्स को भी बंद कर देंगे। मैं इसके बारे में गलत हो सकता है।
बिल के पास

66
BTW '+15' के साथ-साथ '+16' भी काम करता है ... हालांकि इस स्थिति में कोई व्यावहारिक प्रभाव नहीं है।
मेन्कबॉय

15
मेन्कबॉय और ग्रेग की The + 15 ’टिप्पणियां सही हैं, लेकिन मॉलॉक () वैसे भी लगभग 16 तक गोल होगा। +16 का उपयोग करना थोड़ा आसान है। सामान्यीकृत समाधान काल्पनिक रूप से, लेकिन उल्लेखनीय है।
जोनाथन लेफ्लर

6
@Aerovistae: यह थोड़ा मुश्किल सवाल है, और ज्यादातर आपकी समझ पर टिका है कि कैसे एक मनमानी संख्या बनाने के लिए (वास्तव में स्मृति आवंटनकर्ता द्वारा लौटाया गया पता) एक निश्चित आवश्यकता (16 से अधिक) से मेल खाता है। यदि आपको कहा जाता है कि आप 16 के निकटतम गुणक में 53 को राउंड अप करें, तो आप ऐसा कैसे करेंगे? पतों के लिए प्रक्रिया बहुत अलग नहीं है; यह सिर्फ इतना है कि आमतौर पर आप के साथ काम कर रहे नंबर बड़े हैं। मत भूलो, साक्षात्कार के प्रश्न यह जानने के लिए पूछे जाते हैं कि आप कैसे सोचते हैं, यह जानने के लिए नहीं कि आपको उत्तर पता है या नहीं।
जोनाथन लेफ्लर

3
@akristmann: यदि आप <inttypes.h>C99 से उपलब्ध हैं तो मूल कोड सही है (कम से कम प्रारूप स्ट्रिंग के लिए - यकीनन, मान एक कास्ट के साथ पास होना चाहिए :) (uintptr_t)mem, (uintptr_t)ptr। प्रारूप स्ट्रिंग स्ट्रिंग समवर्ती पर निर्भर करता है और PRIXPTR मैक्रो सही printf()लंबाई है और uintptr_tमान के लिए हेक्स आउटपुट के लिए प्रकार निर्दिष्ट करता है । विकल्प का उपयोग करना है %pलेकिन उस से आउटपुट प्लेटफ़ॉर्म द्वारा भिन्न होता है (कुछ एक अग्रणी जोड़ते हैं 0x, सबसे अधिक नहीं) और आमतौर पर निचले-मामले हेक्स अंकों के साथ लिखा जाता है, जिसे मैं नापसंद करता हूं; मैंने जो लिखा है वह सभी प्लेटफार्मों पर एक समान है।
जोनाथन लेफलर

58

तीन अलग-अलग उत्तर के आधार पर आप प्रश्न को कैसे देखते हैं:

1) पूछे गए सटीक सवाल के लिए काफी अच्छा है, जोनाथन लेफ़लर का समाधान, सिवाय इसके कि 16-गठबंधन करने के लिए, आपको केवल 15 अतिरिक्त बाइट्स की आवश्यकता है, 16 को नहीं।

ए:

/* allocate a buffer with room to add 0-15 bytes to ensure 16-alignment */
void *mem = malloc(1024+15);
ASSERT(mem); // some kind of error-handling code
/* round up to multiple of 16: add 15 and then round down by masking */
void *ptr = ((char*)mem+15) & ~ (size_t)0x0F;

बी:

free(mem);

2) अधिक सामान्य मेमोरी आवंटन फ़ंक्शन के लिए, कॉलर को दो पॉइंटर्स (एक का उपयोग करने के लिए और एक को मुक्त करने के लिए) का ट्रैक रखने की आवश्यकता नहीं है। तो आप संरेखित बफर के नीचे 'असली' बफर के लिए एक पॉइंटर स्टोर करें।

ए:

void *mem = malloc(1024+15+sizeof(void*));
if (!mem) return mem;
void *ptr = ((char*)mem+sizeof(void*)+15) & ~ (size_t)0x0F;
((void**)ptr)[-1] = mem;
return ptr;

बी:

if (ptr) free(((void**)ptr)[-1]);

ध्यान दें कि (1) के विपरीत, जहां केवल 15 बाइट्स को मेम के लिए जोड़ा गया था, यह कोड वास्तव में संरेखण को कम कर सकता है यदि आपका कार्यान्वयन मॉलोक से 32-बाइट संरेखण की गारंटी देने के लिए होता है (संभावना नहीं है, लेकिन सिद्धांत रूप में एक सी कार्यान्वयन में 32-बाइट हो सकती है गठबंधन प्रकार)। इससे कोई फर्क नहीं पड़ता कि अगर आप सब करते हैं तो कॉल करना mset_16aligned है, लेकिन यदि आप मेमोरी का उपयोग किसी स्ट्रक्चर के लिए करते हैं तो यह बात हो सकती है।

मुझे यकीन नहीं है कि इसके लिए एक अच्छा निर्धारण क्या है (उपयोगकर्ता को चेतावनी देने के अलावा कि बफर वापस आ गया है जरूरी नहीं कि यह मनमाने ढंग से संरचनाओं के लिए उपयुक्त हो) क्योंकि कार्यक्रम-निर्धारण के लिए कोई रास्ता नहीं है कि कार्यान्वयन-विशिष्ट संरेखण गारंटी क्या है। मुझे लगता है कि स्टार्टअप में आप दो या अधिक 1-बाइट बफ़र आवंटित कर सकते हैं, और मान लें कि आपके द्वारा देखा गया सबसे खराब संरेखण गारंटी संरेखण है। यदि आप गलत हैं, तो आप स्मृति को बर्बाद करते हैं। बेहतर विचार वाला कोई भी हो, कृपया ऐसा कहें ...

[ जोड़ा गया : अपेक्षित मानक संरेखण निर्धारित करने के लिए 'मानक' चाल 'अधिकतम रूप से संरेखित होने की संभावना' का एक संघ बनाने के लिए है। अधिकतम संरेखित प्रकार के होने की संभावना है (C99 में) ' long long', ' long double', ' void *', या ' void (*)(void)'; यदि आप शामिल हैं <stdint.h>, तो आप संभवतः (पावर 6 (AIX) मशीनों के intmax_tस्थान पर ' ' का उपयोग कर सकते हैं , जो आपको 128-बिट पूर्णांक प्रकार देगा)। उस यूनियन के लिए संरेखण आवश्यकताओं को संघ द्वारा पीछा किए गए एकल चार के साथ एक संरचना में एम्बेड करके निर्धारित किया जा सकता है:long longintmax_t

struct alignment
{
    char     c;
    union
    {
        intmax_t      imax;
        long double   ldbl;
        void         *vptr;
        void        (*fptr)(void);
    }        u;
} align_data;
size_t align = (char *)&align_data.u.imax - &align_data.c;

आप तब अनुरोधित संरेखण के बड़े (उदाहरण के लिए, 16) और alignऊपर दिए गए मान का उपयोग करेंगे।

(64-बिट) सोलारिस 10 पर, ऐसा प्रतीत होता है कि परिणाम के लिए मूल संरेखण malloc()32 बाइट्स का एक बहु है।
]

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

3) आपका प्लेटफॉर्म जो प्रदान करता है उसका उपयोग करें: विंडोज पर posix_memalign, POSIX के लिए _aligned_malloc

4) यदि आप C11 का उपयोग करते हैं, तो सबसे साफ - पोर्टेबल और संक्षिप्त - विकल्प मानक लाइब्रेरी फ़ंक्शन का उपयोग करना aligned_allocहै जो भाषा विनिर्देश के इस संस्करण में पेश किया गया था।


1
मैं सहमत हूं - मुझे लगता है कि प्रश्न का आशय यह है कि कोड जो मेमोरी ब्लॉक को मुक्त करता है, केवल 'पका हुआ' 16-बाइट संरेखित पॉइंटर तक पहुंच होगा।
माइकल बूर

1
एक सामान्य समाधान के लिए - आप सही हैं। हालाँकि, प्रश्न में कोड टेम्पलेट दोनों को स्पष्ट रूप से दिखाता है।
जोनाथन लेफ़लर

1
ज़रूर, और एक अच्छे इंटरव्यू में ऐसा होता है कि आप अपना जवाब देते हैं, फिर अगर साक्षात्कारकर्ता मेरा जवाब देखना चाहता है, तो वे इस सवाल को बदल देते हैं।
स्टीव जेसप

1
मुझे ASSERT(mem);आवंटन परिणामों की जांच करने के लिए उपयोग करने पर आपत्ति है ; assertप्रोग्रामिंग त्रुटियों को पकड़ने के लिए है और रन-टाइम संसाधनों की कमी नहीं है।
होवडाल

4
बाइनरी और ए के साथ char *और एक size_tत्रुटि के परिणामस्वरूप उपयोग करना । आपको कुछ का उपयोग करना होगा uintptr_t
मार्को

37

तुम भी posix_memalign()(निश्चित रूप से, POSIX प्लेटफार्मों पर) की कोशिश कर सकते हैं ।


13
और विंडोज पर _aligned_malloc।
स्टीव जेसप

12
कुछ साल बाद इसे जोड़ने पर, "align_alloc" फ़ंक्शन अब C11 विनिर्देश का एक हिस्सा है: open-std.org/jtc1/sc22/wg14/www/docs/n1516.pdf (पेज 346)
स्केडल

20

यहाँ 'राउंड अप' भाग के लिए एक वैकल्पिक तरीका है। सबसे शानदार ढंग से कोडित समाधान नहीं है, लेकिन यह काम हो जाता है, और इस प्रकार का वाक्यविन्यास याद रखना थोड़ा आसान है (प्लस संरेखण मूल्यों के लिए काम करेगा जो 2 की शक्ति नहीं हैं)। uintptr_tकलाकारों संकलक खुश करने के लिए जरूरी हो गया था; सूचक अंकगणित विभाजन या गुणा का बहुत शौकीन नहीं है।

void *mem = malloc(1024 + 15);
void *ptr = (void*) ((uintptr_t) mem + 15) / 16 * 16;
memset_16aligned(ptr, 0, 1024);
free(mem);

2
सामान्य तौर पर, जहां आपने 'अहस्ताक्षरित लंबा लंबा' किया है, आपके पास uintptr_t भी है जो स्पष्ट रूप से डेटा पॉइंटर (शून्य *) धारण करने के लिए पर्याप्त रूप से परिभाषित है। लेकिन आपके समाधान में वास्तव में गुण हैं यदि, किसी कारण से, आपको एक संरेखण की आवश्यकता है जो कि 2. की शक्ति नहीं थी।
जोनाथन लेफ़लर 5

@Andrew: इस प्रकार के सिंटैक्स के लिए अपग्रेड करना याद रखना थोड़ा आसान है (प्लस संरेखण मूल्यों के लिए काम करेगा जो 2 की शक्ति नहीं हैं)
लीजेंड्स 2k

19

दुर्भाग्य से, C99 में किसी भी तरह के संरेखण की गारंटी देना बहुत कठिन है जो कि C99 के अनुरूप किसी भी C कार्यान्वयन के लिए पोर्टेबल होगा। क्यों? क्योंकि एक पॉइंटर "बाइट एड्रेस" होने की गारंटी नहीं है, कोई एक फ्लैट मेमोरी मॉडल के साथ कल्पना कर सकता है। न तो uintptr_t के प्रतिनिधित्व की गारंटी है, जो कि वैसे भी एक वैकल्पिक प्रकार है।

हम कुछ कार्यान्वयनों के बारे में जानते हैं जो शून्य * (और परिभाषा के अनुसार, यह भी चार * ) के लिए एक प्रतिनिधित्व का उपयोग करते हैं , जो कि एक साधारण बाइट पता है, लेकिन C99 द्वारा यह हमारे लिए, प्रोग्रामर के लिए अपारदर्शी है। एक कार्यान्वयन एक सेट { सेगमेंट , ऑफ़सेट } द्वारा एक पॉइंटर का प्रतिनिधित्व कर सकता है, जहां ऑफ़सेट वास्तव में "कौन जानता है-क्या संरेखण" हो सकता है। क्यों, एक पॉइंटर भी हैश टेबल लुकअप वैल्यू या यहां तक ​​कि लिंक्ड-लिस्ट लुकिंग वैल्यू का कुछ रूप हो सकता है। यह सीमाओं की जानकारी सांकेतिक शब्दों में बदलना कर सकता है।

C मानक के लिए हाल ही में C1X ड्राफ़्ट में, हमें _Alignas कीवर्ड दिखाई देता है। वह थोड़ी मदद कर सकता है।

C99 हमें केवल गारंटी देता है कि मेमोरी एलोकेशन फ़ंक्शंस किसी पॉइंटर टाइप पर किसी पॉइंटर पॉइंट के असाइनमेंट के लिए उपयुक्त पॉइंटर लौटाएगा। चूंकि हम वस्तुओं के संरेखण को निर्दिष्ट नहीं कर सकते हैं, हम अपने स्वयं के आवंटन कार्यों को अच्छी तरह से परिभाषित, पोर्टेबल तरीके से संरेखण के लिए जिम्मेदारी के साथ लागू नहीं कर सकते हैं।

इस दावे के बारे में गलत होना अच्छा होगा।


C11 है aligned_alloc()। (C ++ 11/14 / 1z अभी भी नहीं है)। _Alignas()और C ++ alignas()डायनेमिक आवंटन के लिए कुछ भी नहीं करता है, केवल स्वचालित और स्थिर भंडारण (या संरचनात्मक लेआउट) के लिए।
पीटर कॉर्डेस

15

16 बनाम 15 बाइट-काउंट गद्दी के मोर्चे पर, एन का एक संरेखण प्राप्त करने के लिए आपको जो वास्तविक संख्या जोड़ने की आवश्यकता है वह अधिकतम (0, NM) है जहां एम मेमोरी एलोकेटर का प्राकृतिक संरेखण है (और दोनों 2 की शक्तियां हैं)।

चूंकि किसी भी आवंटनकर्ता की न्यूनतम मेमोरी संरेखण 1 बाइट, 15 = अधिकतम (0,16-1) एक रूढ़िवादी उत्तर है। हालाँकि, अगर आपको पता है कि आपका मेमोरी एलोकेटर आपको 32-बिट इंटिग्रेटेड एड्रेस (जो काफी सामान्य है) देने वाला है, तो आप 12 को पैड के रूप में इस्तेमाल कर सकते हैं।

यह इस उदाहरण के लिए महत्वपूर्ण नहीं है, लेकिन यह 12K RAM के साथ एम्बेडेड सिस्टम पर महत्वपूर्ण हो सकता है, जहां हर एक int ने बचत की है।

इसे लागू करने का सबसे अच्छा तरीका यदि आप वास्तव में हर बाइट को बचाने की कोशिश करने जा रहे हैं तो मैक्रो के रूप में है ताकि आप इसे अपनी मूल मेमोरी संरेखण खिला सकें। फिर, यह केवल एम्बेडेड सिस्टम के लिए उपयोगी है जहां आपको हर बाइट को बचाने की आवश्यकता होती है।

नीचे दिए गए उदाहरण में, अधिकांश प्रणालियों पर, मान 1 के लिए ठीक है MEMORY_ALLOCATOR_NATIVE_ALIGNMENT, हालांकि 32-बिट गठबंधन के साथ हमारे सैद्धांतिक एम्बेडेड सिस्टम के लिए, निम्नलिखित कीमती स्मृति का एक छोटा सा बचा सकता है:

#define MEMORY_ALLOCATOR_NATIVE_ALIGNMENT    4
#define ALIGN_PAD2(N,M) (((N)>(M)) ? ((N)-(M)) : 0)
#define ALIGN_PAD(N) ALIGN_PAD2((N), MEMORY_ALLOCATOR_NATIVE_ALIGNMENT)

8

शायद वे ज्ञापन के ज्ञान से संतुष्ट हो गए होंगे ? और जैसा कि जोनाथन लेफ़लर बताते हैं, इसके बारे में जानने के लिए दो नए बेहतर कार्य हैं।

उफ़, फ़्लोरिन ने मुझे मारा। हालाँकि, यदि आप मेरे द्वारा लिंक किए गए मैन पेज को पढ़ते हैं, तो आप सबसे पहले पोस्टर द्वारा दिए गए उदाहरण को समझ पाएंगे।


1
नोट वर्तमान (फरवरी 2016) का संस्करण संदर्भित पृष्ठ कहते हैं, " memalignसमारोह अप्रचलित है और aligned_allocया posix_memalignबजाय प्रयोग किया जाना चाहिए"। मुझे नहीं पता कि अक्टूबर 2008 में इसने क्या कहा था - लेकिन इसका उल्लेख शायद नहीं था क्योंकि इसे aligned_alloc()C11 में जोड़ा गया था।
जोनाथन लेफ़लर

5

हम हर समय Accelerate.framework, एक भारी वेक्टर OS / iOS लाइब्रेरी के लिए इस प्रकार की चीज़ करते हैं, जहाँ हमें हर समय संरेखण पर ध्यान देना पड़ता है। काफी कुछ विकल्प हैं, जिनमें से एक या दो मैंने ऊपर उल्लेख नहीं किया था।

इस तरह के एक छोटे से सरणी के लिए सबसे तेज़ विधि बस स्टैक पर इसे छड़ी है। जीसीसी / क्लैंग के साथ:

 void my_func( void )
 {
     uint8_t array[1024] __attribute__ ((aligned(16)));
     ...
 }

कोई मुफ्त () की आवश्यकता नहीं है। यह आम तौर पर दो निर्देश हैं: स्टैक पॉइंटर से 1024 घटाएं, और फिर स्टैक पॉइंटर को -alignment के साथ। संभवत: आवश्यककर्ता को ढेर पर डेटा की आवश्यकता होती है क्योंकि इसके सरणी का जीवनकाल स्टैक से अधिक हो गया है या पुनरावृत्ति कार्य पर है या स्टैक स्थान एक गंभीर प्रीमियम पर है।

ओएस एक्स / आईओएस पर सभी मॉलॉक / कॉलोक / आदि पर कॉल करते हैं। हमेशा 16 बाइट गठबंधन किया जाता है। यदि आपको उदाहरण के लिए AVX के लिए 32 बाइट संरेखित करने की आवश्यकता है, तो आप posix_memalign का उपयोग कर सकते हैं:

void *buf = NULL;
int err = posix_memalign( &buf, 32 /*alignment*/, 1024 /*size*/);
if( err )
   RunInCirclesWaivingArmsWildly();
...
free(buf);

कुछ लोगों ने C ++ इंटरफ़ेस का उल्लेख किया है जो समान रूप से काम करता है।

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

पनीर: गार्ड मॉलॉक या इसी तरह की बारी। ऐसे बफ़र जो n * 16 बाइट्स आकार के होते हैं जैसे कि यह n * 16 बाइट्स संरेखित होगा, क्योंकि VM का उपयोग ओवररन को पकड़ने के लिए किया जाता है और इसकी सीमाएँ पृष्ठ सीमाओं पर होती हैं।

कुछ Accelerate.framework फ़ंक्शन उपयोगकर्ता को स्क्रैच स्थान के रूप में उपयोग करने के लिए अस्थायी बफ़र की आपूर्ति में लेते हैं। यहां हमें यह मानना ​​होगा कि हमारे पास गया बफर बेतहाशा गलत है और उपयोगकर्ता सक्रिय रूप से हमारे जीवन को कठोर बनाने की कोशिश कर रहा है। (हमारे परीक्षण के मामले अस्थायी बाइट के ठीक बाद और उसके बाद गार्ड पेज को चिपका देते हैं।) यहाँ, हम न्यूनतम आकार लौटाते हैं, हमें इसमें कहीं 16-बाइट संरेखित सेगमेंट की गारंटी देने की आवश्यकता है, और फिर बाद में बफ़र को मैन्युअल रूप से संरेखित करें। यह आकार वांछित है + आकार + संरेखण - 1. तो, इस मामले में 1024 + 16 - 1 = 1039 बाइट्स है। फिर संरेखित करें:

#include <stdint.h>
void My_func( uint8_t *tempBuf, ... )
{
    uint8_t *alignedBuf = (uint8_t*) 
                          (((uintptr_t) tempBuf + ((uintptr_t)alignment-1)) 
                                        & -((uintptr_t) alignment));
    ...
}

संरेखण -1 को जोड़ने से सूचक पहले संरेखित पते से आगे बढ़ जाएगा और फिर -लिंग के साथ -ingignment (जैसे 0xfff ... संरेखण के लिए ff0 = 16) इसे वापस संरेखित पते पर लाता है।

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

जैसा कि align_memset के लिए है, बल्कि यह मूर्खतापूर्ण है। आपको केवल एक संरेखित पते तक पहुंचने के लिए 15 बाइट्स तक लूप करना पड़ता है, और फिर अंत में कुछ संभव सफाई कोड के साथ उसके बाद संरेखित स्टोर के साथ आगे बढ़ना है। आप वेक्टर कोड में क्लीनअप बिट्स भी कर सकते हैं, या तो अनलग्ड स्टोर्स के रूप में जो संरेखित क्षेत्र को ओवरलैप करते हैं (लंबाई प्रदान करना कम से कम एक वेक्टर की लंबाई है) या किसी चीज़ का उपयोग करना। कोई सिर्फ आलसी हो रहा है। हालांकि, यह संभवतः एक उचित साक्षात्कार प्रश्न है यदि साक्षात्कारकर्ता जानना चाहता है कि क्या आप stdint.h, बिटवाइज़ ऑपरेटरों और मेमोरी फंडामेंटल के साथ सहज हैं, इसलिए आकस्मिक उदाहरण को क्षमा किया जा सकता है।


5

मुझे आश्चर्य है कि किसी ने शाओ के जवाब को वोट नहीं दिया है, जैसा कि मैं समझता हूं, मानक C99 में जो पूछा गया है, उसे करना असंभव है, क्योंकि एक सूचक को अभिन्न प्रकार से औपचारिक रूप से परिवर्तित करना अपरिभाषित व्यवहार है। (मानक के अलावा uintptr_t<-> के रूपांतरण की अनुमति देता है void*, लेकिन मानक uintptr_tमूल्य के किसी भी जोड़तोड़ को करने और फिर इसे वापस परिवर्तित करने की अनुमति नहीं देता है ।)


कोई आवश्यकता नहीं है कि एक uintptr_t प्रकार मौजूद है, या यह कि बिट्स का अंतर्निहित सूचक में बिट्स से कोई संबंध है। यदि किसी को भंडारण आवंटित करना था, तो पॉइंटर को स्टोर करें unsigned char* myptr; और उसके बाद `mptr + = (16- (uintptr_t) my_ptr) और 0x0F की गणना करें, व्यवहार को सभी कार्यान्वयनों पर परिभाषित किया जाएगा जो my_ptr को परिभाषित करते हैं, लेकिन क्या परिणामी सूचक संरेखित किया जाएगा यह uintptr_t बिट्स और पते के बीच मैपिंग पर निर्भर करेगा।
सुपरकैट

3

मेमैलिग्न का उपयोग, संरेखित-मेमोरी-ब्लॉक समस्या का एक अच्छा समाधान हो सकता है।


ध्यान दें कि संदर्भित पृष्ठ का वर्तमान (फरवरी 2016) संस्करण "द" कहता हैmemalign समारोह अप्रचलित है और aligned_allocया posix_memalignबजाय प्रयोग किया जाना चाहिए"। मुझे नहीं पता कि अक्टूबर 2010 में इसने क्या कहा था।
जोनाथन लेफ़लर

3

इस प्रश्न को पढ़ते समय पहली चीज जो मेरे सिर में घुसी, वह थी एक संरेखित संरचना को परिभाषित करना, उसे त्वरित करना और फिर इंगित करना।

क्या कोई मूल कारण है जो मुझे याद आ रहा है क्योंकि किसी और ने यह सुझाव नहीं दिया है?

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

यह उन दो प्रणालियों पर काम करता है जिन पर मैंने इसे आजमाया था, लेकिन यह संभव है कि एक कंपाइलर ऑप्टिमाइज़ेशन हो, जिससे मैं कोड की प्रभावकारिता के बारे में मुझे गलत सकारात्मकता देने से अनजान हूँ। मैंनें इस्तेमाल कियाgcc 4.9.2 OSX gcc 5.2.1पर और उबंटू पर ।

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

int main ()
{

   void *mem;

   void *ptr;

   // answer a) here
   struct __attribute__((packed)) s_CozyMem {
       char acSpace[16];
   };

   mem = malloc(sizeof(struct s_CozyMem));
   ptr = mem;

   // memset_16aligned(ptr, 0, 1024);

   // Check if it's aligned
   if(((unsigned long)ptr & 15) == 0) printf("Aligned to 16 bytes.\n");
   else printf("Rubbish.\n");

   // answer b) here
   free(mem);

   return 1;
}

1

MacOS X विशिष्ट:

  1. मॉलॉक के साथ आवंटित सभी संकेत 16 बाइट्स संरेखित हैं।
  2. C11 समर्थित है, इसलिए आप सिर्फ align_malloc (16, आकार) कह सकते हैं।

  3. MacOS X उस कोड को चुनता है जिसे अलग-अलग प्रोसेसरों के लिए बूट समय पर मेमसेट, मेम्ची और मेमोव के लिए ऑप्टिमाइज़ किया जाता है और यह कोड उन ट्रिक्स का उपयोग करता है, जिन्हें आपने कभी तेजी से बनाने के लिए नहीं सुना होगा। 99% संभावना है कि मेमसेट किसी भी हाथ से लिखे मेमसेट 16 की तुलना में तेजी से चलता है जो पूरे प्रश्न को बेकार कर देता है।

यदि आप 100% पोर्टेबल समाधान चाहते हैं, तो C11 से पहले कोई भी नहीं है। क्योंकि एक पॉइंटर के संरेखण का परीक्षण करने का कोई पोर्टेबल तरीका नहीं है। यदि यह 100% पोर्टेबल होना जरूरी नहीं है, तो आप उपयोग कर सकते हैं

char* p = malloc (size + 15);
p += (- (unsigned int) p) % 16;

यह मानता है कि एक सूचक को संरेखित करने के लिए सबसे कम बिट्स में संरेखित किया जाता है जब एक सूचक को अहस्ताक्षरित इंट में परिवर्तित किया जाता है। अहस्ताक्षरित int में जानकारी खोना और कार्यान्वयन को परिभाषित किया गया है, लेकिन इससे कोई फर्क नहीं पड़ता क्योंकि हम परिणाम को वापस सूचक में परिवर्तित नहीं करते हैं।

भयानक हिस्सा निश्चित रूप से है कि मूल सूचक को इसके साथ मुफ्त () कॉल करने के लिए कहीं बचाया जाना चाहिए। तो सभी में मैं वास्तव में इस डिजाइन के ज्ञान पर संदेह करूंगा।


1
आप aligned_mallocओएस एक्स में कहां ढूंढ रहे हैं ? मैं Xcode 6.1 का उपयोग कर रहा हूं और इसे iOS SDK में कहीं भी परिभाषित नहीं किया गया है, न ही इसे कहीं भी घोषित किया गया है /usr/include/*
टॉड लेहमैन

एल कैपिटन पर मैककोड 7.2 के लिए डिट्टो (मैक ओएस एक्स 10.11.3)। C11 फ़ंक्शन किसी भी मामले में है aligned_alloc(), लेकिन वह भी घोषित नहीं है। जीसीसी 5.3.0 से, मुझे दिलचस्प संदेश मिलते हैं alig.c:7:15: error: incompatible implicit declaration of built-in function ‘aligned_alloc’ [-Werror]और alig.c:7:15: note: include ‘<stdlib.h>’ or provide a declaration of ‘aligned_alloc’। कोड वास्तव में किया था शामिल <stdlib.h>, लेकिन न तो -std=c11है और न ही -std=gnu11त्रुटि संदेश बदल दिया है।
जोनाथन लेफ़लर

0

आप कुछ 16 बाइट्स भी जोड़ सकते हैं और फिर पॉइंटर के नीचे मूल (16-मॉड) जोड़कर मूल ptr को 16bit पर धकेलें:

main(){
void *mem1 = malloc(1024+16);
void *mem = ((char*)mem1)+1; // force misalign ( my computer always aligns)
printf ( " ptr = %p \n ", mem );
void *ptr = ((long)mem+16) & ~ 0x0F;
printf ( " aligned ptr = %p \n ", ptr );

printf (" ptr after adding diff mod %p (same as above ) ", (long)mem1 + (16 -((long)mem1%16)) );


free(mem1);
}

0

यदि कोई बाधा है, तो आप एक भी बाइट बर्बाद नहीं कर सकते हैं, तो यह समाधान काम करता है: नोट: एक ऐसा मामला है जहां इसे असीम रूप से निष्पादित किया जा सकता है: डी।

   void *mem;  
   void *ptr;
try:
   mem =  malloc(1024);  
   if (mem % 16 != 0) {  
       free(mem);  
       goto try;
   }  
   ptr = mem;  
   memset_16aligned(ptr, 0, 1024);

एक बहुत अच्छा मौका है कि यदि आप आवंटित करते हैं और फिर एन बाइट्स के एक ब्लॉक को मुक्त करते हैं और फिर एन बाइट्स के दूसरे ब्लॉक का अनुरोध करते हैं, तो मूल ब्लॉक फिर से वापस आ जाएगा। यदि पहले आवंटन संरेखण की आवश्यकता को पूरा नहीं करता है, तो एक अनंत लूप बहुत संभावना है। बेशक, कि सीपीयू के बहुत सारे चक्रों को बर्बाद करने की कीमत पर एक भी बाइट बर्बाद करने से बचा जाता है।
जोनाथन लेफ़लर

क्या आप सुनिश्चित हैं कि %ऑपरेटर को void*सार्थक तरीके से परिभाषित किया गया है?
अजय ब्रह्मक्षत्रिय

0

समाधान के लिए मैंने पैडिंग की एक अवधारणा का उपयोग किया जो स्मृति को संरेखित करता है और एक बाइट की स्मृति को बर्बाद नहीं करता है।

यदि कोई बाधा है, तो आप एक भी बाइट बर्बाद नहीं कर सकते। मॉलॉक के साथ आवंटित सभी संकेत 16 बाइट्स संरेखित हैं।

C11 समर्थित है, जिससे आप कॉल कर सकते हैं aligned_alloc (16, size)

void *mem = malloc(1024+16);
void *ptr = ((char *)mem+16) & ~ 0x0F;
memset_16aligned(ptr, 0, 1024);
free(mem);

1
कई 64-बिट सिस्टम पर, द्वारा लौटाए गए सूचक malloc()को वास्तव में 16-बाइट सीमा पर संरेखित किया जाता है, लेकिन किसी भी मानक गारंटी में कुछ भी नहीं है - यह बस किसी भी उपयोग के लिए पर्याप्त रूप से अच्छी तरह से संरेखित होगा, और कई 32-बिट सिस्टम पर संरेखित करना 8-बाइट सीमा पर्याप्त है, और कुछ के लिए, 4-बाइट सीमा पर्याप्त है।
जोनाथन लेफ़लर

0
size =1024;
alignment = 16;
aligned_size = size +(alignment -(size %  alignment));
mem = malloc(aligned_size);
memset_16aligned(mem, 0, 1024);
free(mem);

आशा है कि यह सबसे सरल कार्यान्वयन है, मुझे अपनी टिप्पणियों से अवगत कराएं।


-3
long add;   
mem = (void*)malloc(1024 +15);
add = (long)mem;
add = add - (add % 16);//align to 16 byte boundary
ptr = (whatever*)(add);

मुझे लगता है कि इसके साथ एक समस्या है क्योंकि आपका ऐड किसी ऐसे स्थान की ओर इशारा करेगा जो मॉलॉक नहीं है - यकीन नहीं होता कि यह कैसे आपके काम आया।
परिणाम

@Sam यह होना चाहिए add += 16 - (add % 16)(2 - (2 % 16)) == 0
एसएस ऐनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.