मूल उत्तर
{
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_alloc
alignment
size
alignment
size
alignment
रिटर्न समारोह रिटर्न या तो एक नल पॉइंटर या आबंटित स्थान के लिए सूचक।
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 फ़ंक्शन एक विकल्प था।
दृश्यों के पीछे, नए संरेखित मेमोरी फ़ंक्शन प्रश्न में उल्लिखित के समान ही काम करते हैं, सिवाय इसके कि वे संरेखण को अधिक आसानी से बाध्य करने की क्षमता रखते हैं, और संरेखित मेमोरी की शुरुआत का ट्रैक आंतरिक रूप से रखते हैं ताकि कोड न हो विशेष रूप से निपटने के लिए है - यह सिर्फ उपयोग किए गए आवंटन फ़ंक्शन द्वारा दी गई मेमोरी को मुक्त करता है।