মধ্যে পার্থক্য কি memmove
এবং memcpy
? আপনি সাধারণত কোনটি ব্যবহার করেন এবং কীভাবে?
মধ্যে পার্থক্য কি memmove
এবং memcpy
? আপনি সাধারণত কোনটি ব্যবহার করেন এবং কীভাবে?
উত্তর:
এর সাথে memcpy
, গন্তব্যটি উত্সটি মোটেই ওভারল্যাপ করতে পারে না। memmove
এটা দিয়ে । এর অর্থ এটি memmove
তুলনামূলকভাবে সামান্য ধীর হতে পারে memcpy
কারণ এটি একই অনুমানগুলি তৈরি করতে পারে না।
উদাহরণস্বরূপ, memcpy
সর্বদা কম থেকে উচ্চে ঠিকানাগুলি অনুলিপি করতে পারে। যদি উত্সটির পরে গন্তব্যটি ওভারল্যাপ হয়ে যায়, এর অর্থ কয়েকটি অনুলিপি অনুলিপি করার আগেই মুছে ফেলা হবে। memmove
এটিকে সনাক্ত করে অন্য দিকে - উচ্চ থেকে নিম্নে - অনুলিপি করবে। তবে এটি পরীক্ষা করে অন্য কোনও (সম্ভবত কম দক্ষ) অ্যালগরিদমে স্যুইচ করতে সময় লাগে।
i = i++ + 1
যেমন ঠিক তেমনি সংজ্ঞায়িত; সংকলক আপনাকে ঠিক সেই কোডটি লিখতে নিষেধ করে না তবে সেই নির্দেশের ফলাফলটি যে কোনও কিছুই হতে পারে এবং বিভিন্ন সংকলক বা সিপিইউগুলি এখানে বিভিন্ন মান দেখায়।
memmove
ওভারল্যাপিং মেমরি পরিচালনা করতে পারে, memcpy
পারে না।
বিবেচনা
char[] str = "foo-bar";
memcpy(&str[3],&str[4],4); //might blow up
স্পষ্টতই উত্স এবং গন্তব্য এখন ওভারল্যাপ হয়ে গেছে, আমরা "বার" দিয়ে "-বার" ওভাররাইট করছি। এটি ব্যবহার অনির্ধারিত আচরণ memcpy
যদি উৎস এবং এই ক্ষেত্রে ক্ষেত্রেই তাই গন্তব্য ওভারল্যাপ আমরা প্রয়োজন memmove
।
memmove(&str[3],&str[4],4); //fine
মধ্যে মূল পার্থক্য memmove()
এবং memcpy()
যে হয় memmove()
একটি বাফার অস্থায়ী মেমরির - - ব্যবহার করা হয়, তাই ওভারল্যাপিং হওয়ার কোনো সম্ভাবনা নেই। অন্যদিকে, উত্স দ্বারা নির্দেশিত অবস্থান থেকে গন্তব্য দ্বারা নির্দেশিত অবস্থানের memcpy()
সরাসরি অবস্থান থেকে ডেটা অনুলিপি করে । ( http://www.cplsplus.com/references/cstring/memcpy/ )
নিম্নলিখিত উদাহরণগুলি বিবেচনা করুন:
#include <stdio.h>
#include <string.h>
int main (void)
{
char string [] = "stackoverflow";
char *first, *second;
first = string;
second = string;
puts(string);
memcpy(first+5, first, 5);
puts(first);
memmove(second+5, second, 5);
puts(second);
return 0;
}
যেমনটি আপনি প্রত্যাশা করেছিলেন, এটি মুদ্রণ করবে:
stackoverflow
stackstacklow
stackstacklow
তবে এই উদাহরণে ফলাফলগুলি একই রকম হবে না:
#include <stdio.h>
#include <string.h>
int main (void)
{
char string [] = "stackoverflow";
char *third, *fourth;
third = string;
fourth = string;
puts(string);
memcpy(third+5, third, 7);
puts(third);
memmove(fourth+5, fourth, 7);
puts(fourth);
return 0;
}
আউটপুট:
stackoverflow
stackstackovw
stackstackstw
এটি কারণ "মেমকিপি ()" নিম্নলিখিতগুলি করে:
1. stackoverflow
2. stacksverflow
3. stacksterflow
4. stackstarflow
5. stackstacflow
6. stackstacklow
7. stackstacksow
8. stackstackstw
memmove()
বাফার ব্যবহারের বাস্তবায়ন প্রয়োজন। এটি জায়গায় স্থানান্তরিত করার পুরোপুরি অধিকারী (যতক্ষণ প্রতিটি পঠন একই ঠিকানায় কোনও লেখার আগে শেষ হয়)।
ধরে নিই যে আপনার উভয়কেই প্রয়োগ করতে হবে, বাস্তবায়নটি এরকম দেখতে পারা যায়:
void memmove ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src < (uintptr_t)dst) {
// Copy from back to front
} else if ((uintptr_t)dst < (uintptr_t)src) {
// Copy from front to back
}
}
void mempy ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src != (uintptr_t)dst) {
// Copy in any way you want
}
}
এবং এটি খুব ভাল পার্থক্য ব্যাখ্যা করা উচিত। memmove
সর্বদা এই জাতীয়ভাবে অনুলিপি করুন যে এটি src
ও নিরাপদ থাকলেও dst
ওভারল্যাপ হয়, memcpy
যখন ব্যবহারের সময় ডকুমেন্টেশন যেমন বলে ঠিক তেমন যত্ন নেয় না memcpy
, দুটি মেমরি অঞ্চল অবশ্যই ওভারল্যাপ করা উচিত নয় ।
উদাহরণস্বরূপ যদি memcpy
অনুলিপিগুলি "সামনে থেকে পিছনে" থাকে এবং মেমরি ব্লকগুলি এটির মতো করে থাকে
[---- src ----]
[---- dst ---]
এর প্রথম বাইট অনুলিপি করে অনুলিপি src
করার dst
আগে এর শেষ বাইটগুলির সামগ্রীটি ইতিমধ্যে নষ্ট করে দেয় src
। কেবলমাত্র "পিছনে সামনের দিকে" অনুলিপি করা সঠিক ফলাফলের দিকে নিয়ে যাবে।
এখন অদলবদল src
এবং dst
:
[---- dst ----]
[---- src ---]
src
সেক্ষেত্রে প্রথম বাইটটি অনুলিপি করার সময় "সামনে থেকে পিছনে" অনুলিপি করা নিরাপদ যেমন "পিছনে সামনের দিকে" অনুলিপি করা হবে এর আগেই এর সম্মুখের কাছে ধ্বংস হয়ে যাবে ।
আপনি লক্ষ করেছেন যে memmove
উপরের বাস্তবায়ন এমনকি যদি তারা ওভারল্যাপ করে তবে এটি পরীক্ষা করে না, এটি কেবল তাদের আপেক্ষিক অবস্থানগুলি পরীক্ষা করে, তবে এটিই অনুলিপিটি নিরাপদ করে তুলবে। যেহেতু memcpy
সাধারণত কোনও সিস্টেমে মেমরি অনুলিপি করার জন্য দ্রুততম উপায় ব্যবহার করে, memmove
সাধারণত তা প্রয়োগ করা হয়:
void memmove ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src < (uintptr_t)dst
&& (uintptr_t)src + count > (uintptr_t)dst
) {
// Copy from back to front
} else if ((uintptr_t)dst < (uintptr_t)src
&& (uintptr_t)dst + count > (uintptr_t)src
) {
// Copy from front to back
} else {
// They don't overlap for sure
memcpy(dst, src, count);
}
}
কখনও কখনও, memcpy
"সর্বদা থেকে পিছনে" বা "পিছনে সামনের দিকে" অনুলিপি করা থাকলে , ওভারল্যাপিংয়ের একটিতে memmove
ব্যবহার memcpy
করা memcpy
যেতে পারে তবে ডেটা কীভাবে সংযুক্ত করা হয় এবং / অথবা কতটা ডেটা থাকতে হবে তার উপর নির্ভর করে অন্যভাবে অনুলিপিও করতে পারে অনুলিপি করা হয়েছে, সুতরাং এমনকি যদি আপনি memcpy
নিজের সিস্টেমে অনুলিপিগুলি পরীক্ষা করে থাকেন তবে আপনি সর্বদা সঠিক হওয়ার জন্য পরীক্ষার ফলাফলের উপর নির্ভর করতে পারবেন না।
কোনটি কল করতে হবে তা সিদ্ধান্ত নেওয়ার সময় এর অর্থ কী?
আপনি যদি নিশ্চিতভাবে না জানেন src
এবং dst
ওভারল্যাপ না memmove
করেন তবে কল করুন এটি সর্বদা সঠিক ফলাফলের দিকে পরিচালিত করবে এবং আপনার প্রয়োজনীয় অনুলিপি মামলার পক্ষে এটি যতটা দ্রুত সম্ভব তত দ্রুত।
আপনি যদি নিশ্চিতভাবে জানেন src
এবং dst
ওভারল্যাপ memcpy
না করেন তবে কল করুন কারণ আপনি ফলাফলটির জন্য যাকে কল করেন তা বিবেচনাধীন নয়, উভয়ই সেই ক্ষেত্রে সঠিকভাবে কাজ করবে, তবে memmove
কখনই দ্রুত হবে না memcpy
এবং আপনি যদি দুর্ভাগ্য হন তবে তা এমনকি হতে পারে ধীর হয়ে উঠুন, যাতে আপনি কেবল কলিং জয় করতে পারেন memcpy
।
কেবল আইএসও / আইইসি: 9899 স্ট্যান্ডার্ড থেকে এটি ভালভাবে বর্ণিত।
7.21.2.1 মেমকি ফাংশন
[...]
2 মেমকি ফাংশনটি এস 2 দ্বারা নির্দেশিত বস্তুর মধ্যে এস 1 দ্বারা নির্দেশিত বস্তু থেকে n অক্ষর অনুলিপি করে। যদি অনুলিপি করা বস্তুগুলির মধ্যে অনুলিপি হয়, তবে আচরণটি সংজ্ঞায়িত।
এবং
7.21.2.2 মেমোমোভ ফাংশন
[...]
2 মেমমোভ ফাংশনটি এস 2 দ্বারা নির্দেশিত বস্তুর মধ্যে এস 1 দ্বারা নির্দেশিত বস্তু থেকে n অক্ষর অনুলিপি করে। অনুলিপিটি সংঘটিত হয় যেমন s2 দ্বারা নির্দেশিত বস্তু থেকে এন অক্ষরগুলি প্রথমে n অক্ষরের অস্থায়ী অ্যারেতে অনুলিপি করা হয় যা s1 এবং s2 দ্বারা নির্দেশিত বস্তুগুলিকে ওভারল্যাপ করে না এবং তারপরে অস্থায়ী অ্যারে থেকে এন অক্ষরগুলি অনুলিপি করা হয় s1 দ্বারা নির্দেশিত বস্তু।
আমি সাধারণত কোনটি প্রশ্নের সাথে আকৃতি ব্যবহার করি তা নির্ভর করে যে আমার কী কার্যকারিতা প্রয়োজন on
সাধারণ পাঠে memcpy()
অনুমতি দেয় না s1
এবং s2
অধিক্রমনের, যখন memmove()
আছে।
প্রয়োগের দুটি সুস্পষ্ট উপায় রয়েছে mempcpy(void *dest, const void *src, size_t n)
(ফেরতের মান উপেক্ষা করে):
for (char *p=src, *q=dest; n-->0; ++p, ++q)
*q=*p;
char *p=src, *q=dest;
while (n-->0)
q[n]=p[n];
প্রথম প্রয়োগে, অনুলিপিটি নিম্ন থেকে উচ্চ ঠিকানাগুলিতে এবং দ্বিতীয়টিতে উচ্চ থেকে নীচে চলে যায়। যদি সীমাটি ওভারল্যাপে অনুলিপি করা হয় (যেমন ফ্রেমবফারটি স্ক্রোল করার ক্ষেত্রে যেমন হয়, উদাহরণস্বরূপ), তবে কেবল অপারেশনের এক দিক সঠিক, এবং অন্যটি সেই অবস্থানগুলি ওভাররাইট করে যা পরবর্তীতে পড়তে হবে।
একটি memmove()
বাস্তবায়ন, এর সহজতম সময়ে, পরীক্ষা করা হবে dest<src
(কিছু প্ল্যাটফর্ম নির্ভর উপায়ে), এবং এর যথাযথ দিকটি কার্যকর করবে memcpy()
।
ব্যবহারকারী কোড অবশ্যই এটি করতে পারে না, কারণ এমনকি কাস্টিংয়ের পরে src
এবং dst
কিছু কংক্রিট পয়েন্টার ধরণের পরেও তারা (সাধারণভাবে) একই বস্তুতে নির্দেশ করে না এবং তাই তুলনা করা যায় না। কিন্তু স্ট্যান্ডার্ড লাইব্রেরিতে অনির্ধারিত আচরণের কারণ ছাড়াই এ জাতীয় তুলনা করার পর্যাপ্ত প্ল্যাটফর্ম জ্ঞান থাকতে পারে।
নোট করুন যে বাস্তব জীবনে, বাস্তবায়নগুলি উল্লেখযোগ্যভাবে আরও জটিল হয়, বৃহত্তর স্থানান্তরগুলি (যখন সারিবদ্ধকরণের অনুমতি দেয়) এবং / অথবা ভাল ডেটা ক্যাশের ব্যবহার থেকে সর্বাধিক কর্মক্ষমতা অর্জন করে। উপরের কোডটি পয়েন্টটি যথাসম্ভব সহজ করার জন্য।
মেমমোভ ওভারল্যাপিং উত্স এবং গন্তব্য অঞ্চলগুলির সাথে ডিল করতে পারে, যখন মেমকিটি পারে না। দুটির মধ্যে মেমকি অনেক বেশি দক্ষ। সুতরাং, আপনি যদি এটি করতে পারেন তবে মেমকিটি ব্যবহার করা আরও ভাল।
তথ্যসূত্র: https://www.youtube.com/watch?v=Yr1YnOVG-4g ডাঃ জেরি কেইন, (স্ট্যানফোর্ড ইন্ট্রো সিস্টেমের বক্তৃতা - 7) সময়: 36:00
memcpy()
এবং না memcopy()
।