কেবলমাত্র মানক পাঠাগার ব্যবহার করে সারিবদ্ধ মেমরি কীভাবে বরাদ্দ করা যায়?


421

আমি একটি কাজের সাক্ষাত্কারের অংশ হিসাবে একটি পরীক্ষা শেষ করেছি, এবং একটি প্রশ্ন আমাকে স্ট্যাম্প করেছে, এমনকি গুগলকে রেফারেন্সের জন্য ব্যবহার করে। আমি দেখতে চাই স্ট্যাকওভারফ্লো ক্রুরা এটি দিয়ে কী করতে পারে:

memset_16alignedফাংশন একটি 16-বাইট প্রান্তিককৃত এটি পাস পয়েন্টার প্রয়োজন, অথবা এটি বিপর্যস্ত হবে।

ক) আপনি কীভাবে 1024 বাইট মেমরি বরাদ্দ করবেন এবং এটি 16 বাইট সীমানায় সারিবদ্ধ করবেন?
খ) memset_16alignedমৃত্যুদন্ড কার্যকর করার পরে স্মৃতি মুক্ত করুন ।

{    
   void *mem;
   void *ptr;

   // answer a) here

   memset_16aligned(ptr, 0, 1024);

   // answer b) here    
}

89
হুম্ম ... দীর্ঘমেয়াদী কোড কার্যকারিতার জন্য, "ফায়ার যিনি মেমসেট_16 লিখেছেন তা স্থির করুন এবং এটি সংশোধন করুন বা এটি প্রতিস্থাপন করুন যাতে এটির একটি অদ্ভুত সীমানা শর্ত না থাকে"
স্টিভেন এ। লো 2

29
অবশ্যই জিজ্ঞাসা করার জন্য একটি বৈধ প্রশ্ন - "অদ্ভুত স্মৃতি প্রান্তিককরণ কেন"। তবে এর সঠিক কারণগুলি থাকতে পারে - এই ক্ষেত্রে, এটি হতে পারে যে মেমসেট_16 এ্যালাইনড () 128-বিট ইন্টিজার ব্যবহার করতে পারে এবং মেমরিটি সারিবদ্ধভাবে জানা থাকলে এটি আরও সহজ। ইত্যাদি
জোনাথন লেফলার

5
যে কেউ মেমসেট লিখেছেন সে অভ্যন্তরীণ লুপটি সাফ করার জন্য অভ্যন্তরীণ 16-বাইট প্রান্তিককরণ এবং নন-প্রান্তিকৃত প্রান্তগুলি পরিষ্কার করতে একটি ছোট ডেটা প্রোলোগ / এপিলোগ ব্যবহার করতে পারে। কোডারগুলি অতিরিক্ত মেমরি পয়েন্টারগুলি হ্যান্ডেল করার চেয়ে এটি আরও সহজ হবে।
আদিসাক

8
কেউ কেন 16 বাইটের সীমানায় ডেটা সারিবদ্ধভাবে চায়? সম্ভবত এটি 128 বিট এসএসই রেজিস্টারগুলিতে লোড করা। আমি বিশ্বাস করি (নবীন) স্বাক্ষরবিহীন মুভিগুলি (যেমন, মুভুপড, এলডিডিকিউ) ধীর গতিতে বা সম্ভবত তারা

11
ঠিকানা সারিবদ্ধ করা ক্যাশে এবং র‌্যামের বিভিন্ন স্তরের (বেশিরভাগ সাধারণ কাজের চাপের জন্য) মধ্যবর্তী উচ্চতর ব্যান্ডউইথের সাথে সাথে ক্যাশের অনুকূলকৃত ব্যবহার বাড়ে। এখানে দেখুন stackoverflow.com/questions/381244/purpose-of-memory-alignment
Deepthought

উত্তর:


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 বিটগুলিকে 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 প্রায় দীর্ঘ সময় থেকে ব্যবহার করছি । যদি ব্যবহারের জন্য ছিল না PRIXPTRprintf()বিবৃতি, এটি যথেষ্ট হবে #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_allocalignmentsizealignmentsizealignment

ফেরত পাঠায় ফাংশন আয় হয় একটি নাল পয়েন্টার বা বরাদ্দ স্থান করার জন্য একটি পয়েন্টার।
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

পর্দার আড়ালে, নতুন প্রান্তিককরণের মেমরি ফাংশন প্রশ্নটিতে বর্ণিত হিসাবে একই কাজ করে, তাদের মধ্যে আরও সহজেই প্রান্তিককরণকে বাধ্য করার ক্ষমতা থাকে না এবং অভ্যন্তরীণভাবে প্রান্তিককরণের মেমরির শুরুতে ট্র্যাক রাখা হয় যাতে কোডটি না করে বিশেষভাবে মোকাবেলা করতে হবে - এটি কেবল ব্যবহৃত বরাদ্দ ফাংশন দিয়ে ফিরে আসা স্মৃতিকে মুক্ত করে।


13
এবং আমি সি ++ এর সাথে মরিচা, তবে আমি সত্যিই বিশ্বাস করি না যে ~ 0x0F সঠিকভাবে পয়েন্টারের আকারে প্রসারিত হবে। যদি এটি না হয় তবে সমস্ত নরক আলগা হয়ে যাবে কারণ আপনি আপনার পয়েন্টারের সর্বাধিক উল্লেখযোগ্য বিটগুলিও মুখোশ করবেন। আমি যদিও এটি সম্পর্কে ভুল হতে পারে।
বিল কে

66
বিটিডাব্লু '+15' পাশাপাশি '+16' কাজ করে ... যদিও এই পরিস্থিতিতে কোনও ব্যবহারিক প্রভাব নেই।
মেনকবয়

15
মেনকবয় এবং গ্রেগের '+ 15' মন্তব্যগুলি সঠিক, তবে ম্যালোক () প্রায় অবশ্যই 16 এর মতো হবে। +16 ব্যবহার করা সহজভাবে ব্যাখ্যা করা সহজ। জেনারেলাইজড সলিউশন অদ্ভুতভাবে, তবে কার্যকর।
জোনাথন লেফলার

6
@ অ্যারোভিস্টে: এটি সামান্য কৌশল সম্পর্কিত প্রশ্ন এবং বেশিরভাগ ক্ষেত্রে কীভাবে একটি স্বেচ্ছাসেবী সংখ্যা করা যায় (যে ঠিকানাটি মেমরি বরাদ্দকারী দ্বারা ফিরে আসে) একটি নির্দিষ্ট প্রয়োজনীয়তার সাথে মিলিত হয় (১ (এর একাধিক)। যদি আপনাকে 53 এর নিকটতম 16 এর একাধিকটি করতে বলা হয়, আপনি কীভাবে এটি করবেন? প্রক্রিয়া ঠিকানাগুলির জন্য খুব আলাদা নয়; এটি হ'ল আপনি সাধারণত যে সংখ্যাগুলি ব্যবহার করছেন সেটি বড়। ভুলে যাবেন না, সাক্ষাত্কারের প্রশ্নগুলি আপনাকে কীভাবে মনে করে তা জানতে জিজ্ঞাসা করা হয়, উত্তরটি জানেন কিনা তা খুঁজে বের করার জন্য নয়।
জোনাথন লেফলার

3
@ ক্রিস্টম্যান: আপনি যদি <inttypes.h>সি 99 থেকে উপলব্ধ থাকেন তবে মূল কোডটি সঠিক (কমপক্ষে বিন্যাসের স্ট্রিংয়ের জন্য - তর্কাতীতভাবে, মানগুলি একটি কাস্টের সাহায্যে পাস করা উচিত (uintptr_t)mem, (uintptr_t)ptr)। ফর্ম্যাট স্ট্রিং স্ট্রিং কনটেনটেশনের উপর নির্ভর করে এবং PRIXPTR ম্যাক্রো printf()একটি uintptr_tমানের জন্য হেক্স আউটপুটের জন্য সঠিক দৈর্ঘ্য এবং টাইপ স্পেসিফায়ার । বিকল্পটি ব্যবহার করা হয় %pতবে প্ল্যাটফর্মের 0xভিত্তিতে আউটপুট পরিবর্তিত হয় (কিছু নেতৃস্থানীয় যোগ করেন , বেশিরভাগ না করেন) এবং সাধারণত লোয়ার-কেস হেক্স ডিজিট দিয়ে লেখা হয়, যা আমি পছন্দ করি না; আমি যা লিখেছি তা প্ল্যাটফর্ম জুড়ে অভিন্ন।
জোনাথন লেফলার

58

আপনি কীভাবে প্রশ্নটির দিকে তাকান তার উপর নির্ভর করে তিনটি ভিন্ন উত্তর:

1) জনাথন লেফলারের সমাধান জিজ্ঞাসা করা সঠিক প্রশ্নের পক্ষে যথেষ্ট ভাল, 16-প্রান্তিককরণের চেয়ে আরও বেশি, আপনার কেবল 16 টি নয়, কেবল অতিরিক্ত 15 বাইট প্রয়োজন।

উত্তর:

/* 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-বাইট থাকতে পারে প্রান্তিক প্রকারের)। আপনি যা কিছু করেন তা কল করুন মেমসেট_6এলইনড করা হলেও তাতে কিছু যায় আসে না, তবে আপনি যদি স্ট্রিমটির জন্য মেমরিটি ব্যবহার করেন তবে তা বিবেচনাধীন হতে পারে।

আমি নিশ্চিত নই যে এর জন্য ভাল ফিক্সটি কী (ব্যবহারকারীকে সতর্ক করা ব্যতীত যে বাফার ফিরে এসেছে তা নির্বিচারে স্ট্রাক্টের জন্য প্রয়োজনীয় উপযুক্ত নয়) যেহেতু বাস্তবায়ন-নির্দিষ্ট প্রান্তিককরণ গ্যারান্টিটি কি কি প্রোগ্রামারিকভাবে নির্ধারণ করার কোনও উপায় নেই। আমি মনে করি প্রারম্ভকালে আপনি দুটি বা আরও 1-বাইট বাফার বরাদ্দ করতে পারেন, এবং ধরে নিবেন যে আপনি দেখতে পান এমন সবচেয়ে খারাপ সারিবদ্ধতা হ'ল গ্যারান্টিযুক্ত প্রান্তিককরণ। যদি আপনি ভুল হন তবে আপনি স্মৃতি নষ্ট করেন। আরও ভাল ধারণা সহ যে কেউ, দয়া করে তাই বলুন ...

[ যুক্ত : 'মানক' কৌশলটি প্রয়োজনীয় প্রান্তিককরণ নির্ধারণ করতে 'সর্বাধিক সারিবদ্ধ প্রকারের সম্ভাব্যগুলির একটি ইউনিয়ন তৈরি করা'। সর্বাধিক সারিবদ্ধ প্রকারেরগুলি (সি 99 এ) হতে পারে ' long long', ' long double', ' void *', বা ' void (*)(void)'; আপনি যদি অন্তর্ভুক্ত করেন তবে আপনি <stdint.h>সম্ভবত ' intmax_t' long long(এবং পাওয়ার 6 (এআইএক্স) মেশিনে) ব্যবহার intmax_tকরতে পারেন, আপনাকে 128-বিট পূর্ণসংখ্যার প্রকার দেবে)। ইউনিয়নের জন্য প্রান্তিককরণের প্রয়োজনীয়তাগুলি ইউনিয়নের পরে একটি একক চরের সাথে স্ট্রাক্ট এ এম্বেড করে নির্ধারণ করা যেতে পারে:

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উপরে গণনা করা মানটি ব্যবহার করবেন।

(-৪-বিট) সোলারিস ১০-এ, দেখা যাচ্ছে যে ফলাফলের জন্য প্রাথমিক বিন্যাসটি malloc()32 বাইটের একাধিক।
]

অনুশীলনে, সারিবদ্ধ বরাদ্দকারীরা প্রায়শই হার্ডওয়ার্ড হওয়ার পরিবর্তে প্রান্তিককরণের জন্য একটি প্যারামিটার নেয়। সুতরাং ব্যবহারকারী তাদের কাঠামোর আকারের আকারটি পাস করবেন (বা এর চেয়ে কম 2 বা তার চেয়ে কম পরিমাণের শক্তি) এবং সমস্ত ভাল হবে।

3) আপনার প্ল্যাটফর্ম যা সরবরাহ করে তা ব্যবহার করুন: উইন্ডোজে posix_memalignপসিক্সের জন্য _aligned_malloc

৪) আপনি যদি সি 11 ব্যবহার করেন তবে সবচেয়ে স্পষ্ট - পোর্টেবল এবং সংক্ষিপ্ত - বিকল্পটি aligned_allocভাষা স্পেসিফিকেশনের এই সংস্করণে প্রবর্তিত স্ট্যান্ডার্ড লাইব্রেরি ফাংশনটি ব্যবহার করা হয় ।


1
আমি সম্মত হই - আমি মনে করি এই প্রশ্নের উদ্দেশ্যটি হ'ল যে মেমোরি ব্লককে মুক্তি দেয় সেই কোডটিতে কেবল 'রান্না করা' 16-বাইট প্রান্তিকিত পয়েন্টারে অ্যাক্সেস থাকবে।
মাইকেল বারার 0

1
সাধারণ সমাধানের জন্য - আপনি ঠিক বলেছেন। যাইহোক, প্রশ্নের কোড টেমপ্লেট উভয়টি পরিষ্কারভাবে দেখায়।
জোনাথন লেফলার

1
অবশ্যই, এবং একটি ভাল সাক্ষাত্কারে যা ঘটে তা হ'ল আপনি আপনার উত্তরটি দিন, তবে যদি সাক্ষাত্কারকারী আমার উত্তর দেখতে চায় তবে তারা প্রশ্ন পরিবর্তন করে।
স্টিভ জেসোপ

1
ASSERT(mem);বরাদ্দের ফলাফল যাচাই করতে আমি আপত্তি জানাই; assertপ্রোগ্রামিং ত্রুটি ধরার জন্য এবং রান-টাইম রিসোর্সের অভাব নয়।
hlovdal

4
একটি সঙ্গে বাইনারি & ব্যবহার char *এবং size_tএকটি ত্রুটি হয়ে যাবে। আপনাকে এরকম কিছু ব্যবহার করতে হবে uintptr_t
মার্কো

37

আপনিও চেষ্টা করতে পারেন posix_memalign()(অবশ্যই পসিক্স প্ল্যাটফর্মগুলিতে)।


13
এবং উইন্ডোতে _সাইনযুক্ত_ম্লোক।
স্টিভ জেসোপ

12
কয়েক বছর পরে এটি যুক্ত করে, "align_alloc" ফাংশনটি এখন C11 স্পেসিফিকেশনের একটি অংশ: ওপেন-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 এর শক্তি নয় এমন প্রান্তিক মানগুলির জন্য কাজ করবে)
কিংবদন্তি

19

দুর্ভাগ্যক্রমে, C99 এ এটি এমনভাবে কোনও ধরণের সারিবদ্ধকরণের গ্যারান্টি দেওয়া বেশ শক্ত বলে মনে হচ্ছে যেটি C99 অনুসারে যে কোনও সি বাস্তবায়ন জুড়ে বহনযোগ্য হবে। কেন? কারণ কোনও পয়েন্টারটিকে "বাইট অ্যাড্রেস" হওয়ার নিশ্চয়তা দেওয়া হয় না এমন একটি ফ্ল্যাট মেমরির মডেল দিয়ে কল্পনা করতে পারে। উভয়ই uintptr_t এর এতটা গ্যারান্টিযুক্ত প্রতিনিধিত্ব নেই , যা নিজেই কোনওভাবে .চ্ছিক প্রকার।

আমরা কিছু বাস্তবায়ন সম্পর্কে জানতে পারি যা অকার্যকর * (এবং সংজ্ঞা অনুসারে, চর * ) এর জন্য একটি প্রতিনিধিত্ব ব্যবহার করে যা একটি সাধারণ বাইট ঠিকানা, তবে সি 99 এর মাধ্যমে প্রোগ্রামাররা আমাদের কাছে এটি অস্বচ্ছ। একটি বাস্তবায়ন কোনও সেট { সেগমেন্ট , অফসেট by দ্বারা পয়েন্টারকে প্রতিনিধিত্ব করতে পারে যেখানে অফসেটে হু -কি অ্যাইনমেন্ট থাকতে পারে "বাস্তবে"। কেন, একটি পয়েন্টার এমনকি হ্যাশ টেবিল দেখার মান, বা এমনকি একটি লিঙ্কযুক্ত-তালিকা দেখার মান কিছু ফর্ম হতে পারে। এটি সীমানা তথ্য এনকোড করতে পারে।

একটি সি স্ট্যান্ডার্ডের জন্য সাম্প্রতিক C1X খসড়াটিতে আমরা _আলিগানাস কীওয়ার্ডটি দেখতে পাই । এটি কিছুটা সাহায্য করতে পারে।

সি 99 আমাদের একমাত্র গ্যারান্টি দেয় যে মেমরি বরাদ্দকরণের কার্যগুলি কোনও অবজেক্টের ধরণের নির্দেশককে নির্দেশের জন্য উপযুক্ত পয়েন্টার ফিরিয়ে দেয়। যেহেতু আমরা অবজেক্টগুলির প্রান্তিককরণ নির্দিষ্ট করতে পারি না, তাই আমরা সঠিকভাবে সংজ্ঞায়িত, বহনযোগ্য পদ্ধতিতে সারিবদ্ধকরণের দায়বদ্ধতার সাথে আমাদের নিজস্ব বরাদ্দ ফাংশনগুলি প্রয়োগ করতে পারি না।

এই দাবিটি সম্পর্কে ভুল হওয়া ভাল হবে।


সি 11 আছে aligned_alloc()। (সি ++ 11/14 / 1z এখনও তা নেই)। _Alignas()এবং সি ++ alignas()গতিশীল বরাদ্দের জন্য কিছুই করবেন না, কেবল স্বয়ংক্রিয় এবং স্ট্যাটিক স্টোরেজ (বা স্ট্রাক্ট বিন্যাস) এর জন্য।
পিটার কর্ডস

15

16 বনাম 15 বাইট-কাউন্টিং প্যাডিংয়ের সম্মুখভাগে, এন এর প্রান্তিককরণ পেতে আপনাকে যে আসল সংখ্যাটি যুক্ত করতে হবে সেটি হ'ল সর্বোচ্চ (0, এনএম) যেখানে এম মেমরি বরাদ্দকারীর প্রাকৃতিক সারিবদ্ধকরণ (এবং উভয়ই 2 এর শক্তি) powers

যেহেতু যে কোনও বরাদ্দকের ন্যূনতম মেমরি প্রান্তিককরণ 1 বাইট হয়, তাই 15 = সর্বোচ্চ (0,16-1) একটি রক্ষণশীল উত্তর। তবে, যদি আপনি জানেন যে আপনার মেমোরি বরাদ্দকারী আপনাকে 32-বিট ইন্টি সারিবদ্ধ ঠিকানাগুলি দেবে (যা মোটামুটি সাধারণ), আপনি 12 টি প্যাড হিসাবে ব্যবহার করতে পারতেন।

এটি এই উদাহরণের জন্য গুরুত্বপূর্ণ নয় তবে এটি 12K র্যাম সহ এম্বেড থাকা সিস্টেমে গুরুত্বপূর্ণ হতে পারে যেখানে প্রতিটি একক আন্তঃসংখ্যক সংরক্ষণ করা হয়।

এটি বাস্তবায়নের সর্বোত্তম উপায় যদি আপনি সম্ভবত প্রতিটি বাইট সংরক্ষণের চেষ্টা করতে চান তবে এটি ম্যাক্রো হিসাবে রয়েছে যাতে আপনি এটি আপনার আদি মেমরির সারিবদ্ধতা খাওয়াতে পারেন। আবার এটি সম্ভবত এমবেড হওয়া সিস্টেমগুলির জন্যই দরকারী যেখানে আপনাকে প্রতিটি বাইট সংরক্ষণ করতে হবে।

নীচের উদাহরণে, বেশিরভাগ সিস্টেমে, মান 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পরিবর্তে ব্যবহার করা উচিত"। আমি জানি না এটি ২০০৮ সালের অক্টোবরে কী বলেছিল - তবে এটি সম্ভবত aligned_alloc()সি ১১-এ যুক্ত হওয়ার কারণে উল্লেখ করেনি।
জোনাথন লেফলার

5

আমরা এক্সিলারেট.ফ্রেমওয়ার্কের জন্য এই ধরণের কাজটি সর্বদা করি, একটি ভারী ভেক্টরাইজড ওএস এক্স / আইওএস লাইব্রেরি, যেখানে আমাদের সারাক্ষণ সারিবদ্ধকরণের দিকে মনোযোগ দিতে হয়। বেশ কয়েকটি বিকল্প রয়েছে, যার মধ্যে একটি বা দুটি আমি উপরে বর্ণিত দেখিনি।

এর মতো একটি ছোট অ্যারের দ্রুততম পদ্ধতিটি কেবল স্ট্যাকের সাথে এটি আটকে রাখা। জিসিসি / বিড়ম্বনা সহ:

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

কোনও ফ্রি () দরকার নেই। এটি সাধারণত দুটি নির্দেশ: স্ট্যাক পয়েন্টার থেকে 1024 বিয়োগ করুন, তারপরে এবং -স্টাইনমেন্ট সহ স্ট্যাক পয়েন্টার। সম্ভবত অনুরোধকারীকে স্তূপে থাকা ডেটার দরকার ছিল কারণ এর অ্যারের আয়ু স্ট্যাক ছাড়িয়েছে বা পুনরাবৃত্তি কাজ করছে বা স্ট্যাক স্পেসটি মারাত্মক প্রিমিয়ামে রয়েছে।

ওএস এক্স / আইওএস-এ সমস্ত কল ম্যালোক / কলোক / ইত্যাদি। সর্বদা 16 বাইট সারিবদ্ধ হয় আপনার যদি অ্যাভিএক্সের জন্য 32 বাইট প্রান্তিককরণের প্রয়োজন হয়, উদাহরণস্বরূপ, তবে আপনি posix_memalign ব্যবহার করতে পারেন:

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

কিছু লোক সি ++ ইন্টারফেস উল্লেখ করেছে যা একইভাবে কাজ করে।

এটি ভুলে যাওয়া উচিত নয় যে পৃষ্ঠাগুলি দুটি বৃহত্তর শক্তির সাথে সংযুক্ত থাকে, সুতরাং পৃষ্ঠা-প্রান্তিকিত বাফারগুলি 16 বাইট প্রান্তিককরণ হয়। সুতরাং, এমএমএপ () এবং ভ্যালোক () এবং অন্যান্য অনুরূপ ইন্টারফেসগুলিও বিকল্প। এমএমএপ () এর সুবিধা রয়েছে যে আপনি চাইলে বাফারটিতে শূন্যহীন কিছু দিয়ে পূর্বনির্ধারিত বরাদ্দ দেওয়া যেতে পারে। যেহেতু এগুলির পৃষ্ঠার প্রান্তরেখা রয়েছে তাই আপনি এগুলি থেকে ন্যূনতম বরাদ্দ পাবেন না এবং আপনি প্রথমবার এটি স্পর্শ করার পরে এটি কোনও ভিএম ত্রুটির শিকার হতে পারে।

চিজি: গার্ড ম্যালোক বা অনুরূপ চালু করুন। এই জাতীয় আকারের এন * ১ n বাইটযুক্ত বাফারগুলি এন * ১ 16 বাইট প্রান্তিককরণ করা হবে, কারণ ভিএম ওভাররানগুলি ধরতে ব্যবহৃত হয় এবং এর সীমানা পৃষ্ঠা সীমানায় থাকে।

কিছু ত্বরান্বিত.ফ্রেমওয়ার্ক ফাংশন স্ক্র্যাচ স্পেস হিসাবে ব্যবহারের জন্য কোনও সরবরাহকারী টেম্প বাফার গ্রহণ করে। এখানে আমাদের ধরে নিতে হবে যে আমাদের কাছে পৌঁছে দেওয়া বাফারটি বুনোভাবে ভুলভাবে ভুলভাবে চালিত হয়েছে এবং ব্যবহারকারী সক্রিয়ভাবে আমাদের জীবনকে তীব্রতর করে তোলার চেষ্টা করছেন। (আমাদের পরীক্ষাগুলির ক্ষেত্রে তাত্পর্যপূর্ণ বাফারটির ঠিক আগে এবং তার পরেও একটি রক্ষাকারীর পৃষ্ঠায় লিখিত থাকে)) এখানে আমরা সর্বনিম্ন আকারটি ফিরে পাই যেখানে এটির কোথাও কোনও 16-বাইট প্রান্তিককরণ অংশের গ্যারান্টি দিতে হবে এবং তারপরে ম্যানুয়ালি বাফারটিকে সারিবদ্ধভাবে প্রান্তিককরণ করতে হবে। এই আকারটি পছন্দসই_ আকার + প্রান্তিককরণ - ১. সুতরাং, এই ক্ষেত্রে 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));
    ...
}

প্রান্তিককরণ -১ যোগ করা হলে প্রথম সারিবদ্ধ ঠিকানাটির পরে পয়েন্টারটি সরানো হবে এবং তারপরে অ্যালিং-এর সাথে এলাইনমেন্ট (উদাহরণস্বরূপ 0xfff ... ff0 for alignment = 16) এটিকে পুনরায় সাজানো ঠিকানায় ফিরিয়ে আনবে।

অন্যান্য পোস্টগুলির দ্বারা বর্ণিত হিসাবে, 16-বাইট প্রান্তিককরণ গ্যারান্টি ছাড়াই অন্য অপারেটিং সিস্টেমে আপনি বড় আকারের সাথে ম্যালোক কল করতে পারেন, বিন্দুটি ফ্রি () পরে আলাদা করে রাখতে পারেন, তারপরে উপরে বর্ণিত অনুসারে সারিবদ্ধ করুন এবং প্রান্তিক বিন্দুটি ব্যবহার করুন, যতটা আমাদের টেম্প বাফারের ক্ষেত্রে বর্ণিত described

সারিবদ্ধ_মেস্ট হিসাবে, এটি বরং নির্বোধ। একটি প্রান্তিক ঠিকানাতে পৌঁছানোর জন্য আপনাকে কেবল 15 বাইট অবধি লুপ করতে হবে এবং তারপরে শেষে কিছু সম্ভাব্য ক্লিনআপ কোড সহ প্রান্তিককরণ স্টোরগুলি দিয়ে এগিয়ে যেতে হবে। এমনকি আপনি ভেক্টর কোডে ক্লিনআপ বিটগুলিও করতে পারেন, না হয় স্বাক্ষরযুক্ত স্টোরগুলি যা প্রান্তিক অঞ্চলে ওভারল্যাপ করে (দৈর্ঘ্য কমপক্ষে কোনও ভেক্টরের দৈর্ঘ্য সরবরাহ করা হয়) বা মুভমাস্কডিকিউয়ের মতো কিছু ব্যবহার করে। কেউ সবে অলস হয়ে যাচ্ছেন। তবে, সম্ভবত এটি একটি যুক্তিসঙ্গত সাক্ষাত্কারের প্রশ্ন যদি ইন্টারভিউওয়ালা যদি আপনি জানতে চান যে আপনি stdint.h, বিটওয়াইজ অপারেটর এবং মেমরি ফান্ডামেন্টালগুলির সাথে স্বাচ্ছন্দ্য বোধ করেন, তবে দ্বন্দ্বযুক্ত উদাহরণটি ক্ষমা করা যেতে পারে।


5

আমি বিস্মিত Noone এর ভোট দিয়েছেন আছি শাও এর উত্তর যে, আমি এটা বুঝতে, এটা কি, মানক C99 জিজ্ঞাসা করছে অবিচ্ছেদ্য টাইপ একটি পয়েন্টার রূপান্তর যেহেতু আনুষ্ঠানিকভাবে অনির্ধারিত আচরণ কি করা অসম্ভব। (মানক uintptr_t<-> রূপান্তরকরণের মান ব্যতীত void*, তবে uintptr_tমানটি মানটির কোনও হেরফের করতে পারে না এবং এটি আবার রূপান্তর করতে পারে বলে মনে হয় না ))


কোনও uintptr_t প্রকারের অস্তিত্বের প্রয়োজন নেই বা এর বিটগুলির অন্তর্নিহিত পয়েন্টারে বিটের সাথে কোনও সম্পর্ক রয়েছে। যদি কেউ স্টোর অতিরিক্ত বরাদ্দ করে থাকে তবে পয়েন্টারটিকে একটি হিসাবে সংরক্ষণ করুন unsigned char* myptr; এবং তারপরে ute mptr + = (16- (uintptr_t) my_ptr) এবং 0x0F গণনা করুন, আচরণটি my_ptr সংজ্ঞায়িত সমস্ত প্রয়োগের উপর সংজ্ঞায়িত হবে তবে ফলাফল পয়েন্টারটি একত্রিত হবে কিনা তা uintptr_t বিট এবং ঠিকানার মধ্যে ম্যাপিংয়ের উপর নির্ভর করবে।
সুপারক্যাট

3

মেমালাইনগাইন, অ্যালাইনড -মেমোরি-ব্লকগুলির ব্যবহার সমস্যার সমাধান হতে পারে।


নোট বর্তমান (ফেব্রুয়ারি 2016) এর যে সংস্করণটি রেফারেন্সড পৃষ্ঠা বলেন, " memalignফাংশন অপ্রচলিত এবং aligned_allocবা posix_memalignপরিবর্তে ব্যবহার করা উচিত"। 2010 সালের অক্টোবরে এটি কী বলেছিল তা আমি জানি না
জোনাথন লেফলার 12'16

3

এই প্রশ্নটি পড়ার সময় প্রথম যে বিষয়টি আমার মাথায় popুকে পড়েছিল তা হ'ল একটি প্রান্তিক কাঠামো সংজ্ঞা দেওয়া, তা ইনস্ট্যান্টিয়েট করা এবং তারপরে এটি নির্দেশ করা।

অন্য কেউ এটির পরামর্শ না দেওয়ার কারণে কি আমি নিখোঁজ রয়েছি?

সাইডেনোট হিসাবে, যেহেতু আমি চরের একটি অ্যারে ব্যবহার করেছি (ধরে নিলাম সিস্টেমের চরটি 8 টি বিট (অর্থাত্ 1 বাইট)), আমি প্রয়োজনীয়তার প্রয়োজন দেখছি না __attribute__((packed))(আমি ভুল হলে আমাকে সংশোধন করব), তবে আমি এটি রেখেছি যেকোন ভাবে.

এটি দুটি সিস্টেমে কাজ করে যা আমি এটি চেষ্টা করেছিলাম, তবে এটি সম্ভব যে একটি সংকলক অপ্টিমাইজেশন রয়েছে যা আমি কোডের কার্যকারিতা ভুয়া আমাকে মিথ্যা ধনাত্মক দিতে অসচেতন। আমি gcc 4.9.2ওএসএক্স এবং 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

ম্যাকোস এক্স নির্দিষ্ট:

  1. ম্যালোকের সাথে বরাদ্দকৃত সমস্ত পয়েন্টার 16 বাইট সারিবদ্ধ হয়।
  2. সি 11 সমর্থিত, যাতে আপনি কেবল এলাইন_ম্লোককে (16, আকার) কল করতে পারেন।

  3. ম্যাকোস এক্স কোডটি পিক করে যা মেমসেট, মেমকি এবং মেমমোভের জন্য বুট সময়ে পৃথক প্রসেসরের জন্য অনুকূলিত হয় এবং সেই কোডটি এমন কৌশলগুলি ব্যবহার করে যা আপনি এটিকে দ্রুত করতে কখনও শুনেন নি। 99% সুযোগ যে মেমসেটটি কোনও হাতে লিখিত মেমসেট 16 এর চেয়ে দ্রুত চলে যা পুরো প্রশ্নটিকে অর্থহীন করে তোলে।

আপনি যদি 100% পোর্টেবল সমাধান চান তবে সি 11 এর আগে আর কিছু নেই। কারণ পয়েন্টারের সারিবদ্ধতা পরীক্ষা করার কোনও বহনযোগ্য উপায় নেই। যদি এটি 100% পোর্টেবল না হয়, আপনি ব্যবহার করতে পারেন

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

এটি ধরে নিয়েছে যে একটি পয়েন্টারকে স্বাক্ষরযুক্ত ইনতে রূপান্তর করার সময় একটি পয়েন্টারের সারিবদ্ধতা সর্বনিম্ন বিটগুলিতে সংরক্ষণ করা হয়। স্বাক্ষরবিহীন ইন্টিতে রূপান্তর তথ্য হারায় এবং এটি বাস্তবায়িত সংজ্ঞায়িত হয় তবে এটি কার্যকর নয় কারণ আমরা ফলাফলটিকে আবার কোনও পয়েন্টারে রূপান্তর করি না।

ভয়াবহ অংশটি অবশ্যই এটির সাথে ফ্রি () কল করতে মূল পয়েন্টারটি অবশ্যই কোথাও সংরক্ষণ করতে হবে। সব মিলিয়ে আমি সত্যিই এই নকশার বুদ্ধি সম্পর্কে সন্দেহ করব।


1
aligned_mallocওএস এক্সে আপনি কোথায় সন্ধান করছেন? আমি এক্সকোড 6.1 ব্যবহার করছি এবং এটি আইওএস এসডিকে কোথাও সংজ্ঞায়িত করা হয়নি, বা এটি কোথাও ঘোষিতও নয় /usr/include/*
টড লেহম্যান

এল ক্যাপিটেনে এক্সকোড 7.2 এর মিতু (ম্যাক ওএস এক্স 10.11.3)। সি 11 ফাংশনটি কোনও অবস্থাতেই 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-মোড) যুক্ত করে মূল পিটিআরটি 16 বেটে প্রান্তিককরণে চাপতে পারেন:

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 বাইট সারিবদ্ধ হয়।

সি 11 সমর্থিত, যাতে আপনি কেবল কল করতে পারেন aligned_alloc (16, size)

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

1
অনেকগুলি -৪-বিট সিস্টেমে পয়েন্টারটি malloc()প্রকৃতপক্ষে ১--বাইট সীমানায় সারিবদ্ধ হয় তবে কোনও মানের কোনও গ্যারান্টি দেয় না যে - এটি কেবল কোনও ব্যবহারের জন্য যথেষ্ট ভালভাবে সাজানো থাকবে এবং অনেকগুলি 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);

আশা করি এটিই একটি সহজ বাস্তবায়ন, আমাকে আপনার মন্তব্যগুলি জানান know


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

আমি মনে করি এটিতে কোনও সমস্যা আছে কারণ আপনার অ্যাডটি এমন কোনও জায়গায় নির্দেশ করবে যা ম্যালোকড নয় - এটি কীভাবে আপনার কাজ করে তা নিশ্চিত নয়।
resultsway

@ সাম এটি হওয়া উচিত add += 16 - (add % 16)(2 - (2 % 16)) == 0
এসএস আন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.