আসল উত্তর
{
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 বিটগুলিকে 0 এ পুনরায় সেট করতে চাই 0 0x0F এর সর্বশেষ 4 বিট এক সেট করা আছে; অতএব, ~0x0F
সর্বশেষ বিট ব্যতীত সমস্ত বিট একটিতে সেট করা আছে। 0x800011 দিয়ে এন্ডিং 0x800010 দেয়। আপনি অন্যান্য অফসেটগুলিতে পুনরাবৃত্তি করতে পারেন এবং দেখতে পাচ্ছেন যে একই গাণিতিক কাজ করে।
শেষ ধাপে, free()
সবসময় আপনি, এবং শুধুমাত্র, এর আগমন: সহজ free()
একটি মানের যে এক malloc()
, calloc()
বা realloc()
আপনি ফিরে - অন্য কিছু একটি দুর্যোগ। আপনি সঠিকভাবে এই mem
মানটি ধরে রাখতে পেরেছেন - আপনাকে ধন্যবাদ। ফ্রি এটি প্রকাশ করে s
অবশেষে, আপনি যদি আপনার সিস্টেমের malloc
প্যাকেজের ইন্টার্নালগুলি সম্পর্কে জানেন তবে আপনি অনুমান করতে পারেন যে এটি 16-বাইট সারিবদ্ধ ডেটা (বা এটি 8-বাইট সারিবদ্ধ হতে পারে) ভালভাবে ফিরে আসতে পারে। যদি এটি 16-বাইট সারিবদ্ধ হয়, তবে আপনাকে মানগুলির সাথে ডুব দেওয়ার দরকার পড়বে না। যাইহোক, এটি মজাদার এবং বহনযোগ্য নয় - অন্যান্য malloc
প্যাকেজগুলির বিভিন্ন ন্যূনতম প্রান্তিককরণ রয়েছে, এবং তাই কোনও জিনিস যখন আলাদা কিছু করে তখন এটি মূল ডাম্পগুলিতে নিয়ে যায় um বিস্তৃত সীমাবদ্ধতার মধ্যে, এই সমাধানটি বহনযোগ্য।
posix_memalign()
সারিবদ্ধ স্মৃতি পেতে অন্য কেউ উল্লেখ করেছেন; যা সর্বত্র পাওয়া যায় না, তবে প্রায়শই এটি ভিত্তি হিসাবে ব্যবহার করে প্রয়োগ করা যেতে পারে। নোট করুন যে এটি সুবিধাজনক ছিল যে প্রান্তিককরণটি 2 এর শক্তি ছিল; অন্যান্য সারিবদ্ধতা মেসেঞ্জার হয়।
আরও একটি মন্তব্য - এই কোড বরাদ্দ সফল হয়েছে তা পরীক্ষা করে না।
সংশোধন
উইন্ডোজ প্রোগ্রামার উল্লেখ করেছে যে আপনি পয়েন্টারগুলিতে বিট মাস্ক অপারেশন করতে পারবেন না, এবং প্রকৃতপক্ষে, জিসিসি (৩.৪..6 এবং ৪.৩.১ পরীক্ষা করা হয়েছে) এর মতো অভিযোগ করে। সুতরাং, বেসিক কোডের একটি সংশোধিত সংস্করণ - একটি প্রধান প্রোগ্রামে রূপান্তরিত হয়েছে, এরপরে অনুসরণ করা হবে। আমি 16 এর পরিবর্তে মাত্র 15 যুক্ত করার স্বাধীনতা নিয়েছি, যেমনটি উল্লেখ করা হয়েছে। uintptr_t
বেশিরভাগ প্ল্যাটফর্মগুলিতে অ্যাক্সেসযোগ্য হওয়ার জন্য C99 প্রায় দীর্ঘ সময় থেকে ব্যবহার করছি । যদি ব্যবহারের জন্য ছিল না PRIXPTR
এ printf()
বিবৃতি, এটি যথেষ্ট হবে #include <stdint.h>
ব্যবহার পরিবর্তে #include <inttypes.h>
। [এই কোডটিতে সিআর দ্বারা নির্দেশিত ফিক্স অন্তর্ভুক্ত রয়েছে , যা বিল কে দ্বারা বেশ কয়েক বছর আগে প্রথম তৈরি করা একটি পয়েন্টটি পুনরুক্ত করছিল , যা আমি এখনও অবহেলা করতে সক্ষম হয়েছি।]
#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()
সাধারণ উদ্দেশ্যে বরাদ্দকরণের ক্রিয়ায় রূপান্তর করতে , বরাদ্দকারীর একক রিটার্ন মানকে রিলিজের ঠিকানাটি এনকোড করতে হবে, কারণ বেশিরভাগ লোক তাদের উত্তরে নির্দেশ করেছে।
সাক্ষাত্কারে সমস্যা
উরি মন্তব্য করেছিলেন: সম্ভবত আমার আজ সকালে [a] পড়ার বোঝার সমস্যা হচ্ছে, তবে যদি সাক্ষাত্কারের প্রশ্নটি সুনির্দিষ্টভাবে বলে: "আপনি কীভাবে 1024 বাইট মেমরি বরাদ্দ করবেন" এবং আপনি স্পষ্টভাবে তার চেয়ে বেশি বরাদ্দ রাখবেন। সাক্ষাত্কারকারীর কাছ থেকে এটি কি স্বয়ংক্রিয় ব্যর্থতা হবে না?
আমার প্রতিক্রিয়া 300-চরিত্রের মন্তব্যে মাপসই হবে না ...
এটা নির্ভর করে, আমার ধারণা। আমি মনে করি বেশিরভাগ লোকেরা (আমাকে সহ) এই প্রশ্নটি গ্রহণ করেছিল "আপনি কীভাবে একটি স্থান বরাদ্দ করবেন যেখানে 1024 বাইট ডেটা সংরক্ষণ করা যায় এবং যেখানে বেস ঠিকানাটি 16 বাইটের একাধিক"। যদি সাক্ষাত্কারকারীর সত্যিই বোঝানো হয় আপনি কীভাবে 1024 বাইট (কেবলমাত্র) বরাদ্দ করতে পারেন এবং এটি 16-বাইট সারিবদ্ধ করেছেন, তবে বিকল্পগুলি আরও সীমাবদ্ধ।
- স্পষ্টতই, একটি সম্ভাবনা হ'ল 1024 বাইট বরাদ্দ করা এবং তারপরে সেই ঠিকানাটি 'প্রান্তিককরণ চিকিত্সা' দেওয়া; এই পদ্ধতির সমস্যাটি হ'ল আসল উপলভ্য স্থানটি সঠিকভাবে নির্ধারণ করা হয়নি (ব্যবহারযোগ্য স্থানটি 1008 এবং 1024 বাইটের মধ্যে রয়েছে, তবে কোন আকারটি নির্দিষ্ট করার জন্য কোনও ব্যবস্থা উপলব্ধ ছিল না), যা এটিকে দরকারীের চেয়ে কম উপস্থাপন করে।
- আরেকটি সম্ভাবনা হ'ল আপনি একটি সম্পূর্ণ মেমরি বরাদ্দকারী লিখেছেন এবং আপনি যে 1024-বাইট ব্লকটি ফিরে আসছেন তা যথাযথভাবে প্রান্তিক করা হয়েছে কিনা তা নিশ্চিত হওয়া উচিত। যদি এটি হয় তবে আপনি সম্ভবত প্রস্তাবিত সমাধান যা করেছেন তার সাথে মোটামুটি একইভাবে একটি অপারেশন শেষ করবেন, তবে আপনি এটি বরাদ্দকারীর ভিতরে লুকিয়ে রাখবেন।
যাইহোক, যদি সাক্ষাত্কারকারীর মধ্যে উভয় প্রতিক্রিয়াগুলির প্রত্যাশা থাকে তবে আমি তাদের কাছে প্রত্যাশা করব যে এই সমাধানটি একটি ঘনিষ্ঠভাবে সম্পর্কিত প্রশ্নের উত্তর দেয় এবং তারপরে কথোপকথনটি সঠিক দিকে নির্দেশ করার জন্য তাদের প্রশ্নটি পুনরায় প্রত্যাখ্যান করে। (তদুপরি, যদি সাক্ষাত্কারকারীর সত্যিকার অর্থে কৃপণ হয়ে ওঠে, তবে আমি কাজটি চাইব না; যদি অপর্যাপ্ত নির্ভুল প্রয়োজনের উত্তরটি সংশোধন না করে শিখায় নিক্ষেপ করা হয়, তবে সাক্ষাত্কারকারীর পক্ষে এটি কাজ করা নিরাপদ নয়।)
পৃথিবী এগিয়ে যায়
প্রশ্নের শিরোনামটি সম্প্রতি পরিবর্তিত হয়েছে। এটি সি সাক্ষাত্কারের প্রশ্নে মেমরি সারিবদ্ধতা সমাধান করেছিল যা আমাকে আটকে দিয়েছে । সংশোধিত শিরোনাম ( কীভাবে কেবল প্রমিত লাইব্রেরি ব্যবহার করে সারিবদ্ধ মেমরি বরাদ্দ করা যায়? ) কিছুটা সংশোধিত উত্তর দাবি করে - এই সংযোজন এটি সরবরাহ করে।
সি 11 (আইএসও / আইইসি 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_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()
শূন্য ফিরে আসবে; অন্যথায়, ত্রুটিটি নির্দেশ করতে একটি ত্রুটি নম্বর ফিরিয়ে দেওয়া হবে।
হয় বা এই উভয়ই এখন প্রশ্নের উত্তর দিতে ব্যবহার করা যেতে পারে, তবে প্রশ্নের মূল উত্তর দেওয়া হয়েছিল কেবল পসিক্স ফাংশনই an
পর্দার আড়ালে, নতুন প্রান্তিককরণের মেমরি ফাংশন প্রশ্নটিতে বর্ণিত হিসাবে একই কাজ করে, তাদের মধ্যে আরও সহজেই প্রান্তিককরণকে বাধ্য করার ক্ষমতা থাকে না এবং অভ্যন্তরীণভাবে প্রান্তিককরণের মেমরির শুরুতে ট্র্যাক রাখা হয় যাতে কোডটি না করে বিশেষভাবে মোকাবেলা করতে হবে - এটি কেবল ব্যবহৃত বরাদ্দ ফাংশন দিয়ে ফিরে আসা স্মৃতিকে মুক্ত করে।