কেন ফাংশন পয়েন্টার এবং ডেটা পয়েন্টার সি / সি ++ এ বেমানান?


130

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


16
POSIX এ সংজ্ঞায়িত স্ট্যান্ডার্ড সি-তে অপরিবর্তিত। পার্থক্য মনে।
প্রথম

আমি এতে সামান্য নতুন, তবে আপনার "=" এর ডানদিকে কাস্ট করার কথা নেই? সমস্যাটি আমার কাছে মনে হচ্ছে সমস্যাটি হ'ল আপনি একটি শূন্য পয়েন্টারকে অর্পণ করছেন। তবে আমি দেখতে পাচ্ছি যে ম্যান পেজটি এটি করে, তাই আশা করি কেউ আমাকে শিক্ষিত করতে পারে। আমি dlsym থেকে রিটার্ন মান ingালু লোকের নেট উদাহরণগুলি দেখতে পাই, যেমন এখানে: daniweb.com/forums/thread62561.html
জেসনউফ

9
তথ্য প্রকারের বিভাগে পসিএক্সvoidvoid *void *
জোনাথন লেফলার

2
এই ওয়েবসাইটটির প্রায় বিভাগে এটিই প্রশ্ন .. :) :) আপনাকে এখানে প্রশ্নটি দেখুন
চিড়িয়াখানা

1
@ কিথথম্পসন: বিশ্ব বদলে যায় - এবং পসিক্সও তা করে। আমি যা লিখেছি তা ২০১২ সালে আর প্রযোজ্য না। পসিক্স মানটি ভার্চিয়াটি পরিবর্তন করে। এটি এখন এর সাথে যুক্ত dlsym()- 'অ্যাপ্লিকেশন ব্যবহার' বিভাগের শেষটি নোট করুনvoid *fptr = (int (*)(int))dlsym(handle, "my_function");
জোনাথন লেফলার

উত্তর:


171

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


15
এছাড়াও, কোড এবং ডেটা শারীরিক হার্ডওয়্যারে একই জায়গায় সঞ্চয় করা থাকলেও, সফ্টওয়্যার এবং মেমরি অ্যাক্সেস প্রায়শই অপারেটিং সিস্টেম "অনুমোদন" ছাড়াই কোড হিসাবে চলমান ডেটা রোধ করে। ডিইপি এবং মত।
মাইকেল গ্র্যাসেক

15
কমপক্ষে আলাদা আলাদা অ্যাড্রেস স্পেস থাকা (যত বেশি গুরুত্বপূর্ণ) তত গুরুত্বপূর্ণ যে ফাংশন পয়েন্টারগুলিতে ডেটা পয়েন্টারগুলির চেয়ে আলাদা উপস্থাপনা থাকতে পারে।
মাইকেল

14
এমনকি আলাদা ঠিকানাগুলির স্পেস ব্যবহার করে কোড এবং ডেটা পয়েন্টার রাখার জন্য আপনার হার্ভার্ডের আর্কিটেকচারও লাগবে না - পুরানো ডস "ছোট" মেমোরি মডেল এটি করেছে (সাথে পয়েন্টারগুলির নিকটবর্তী CS != DS)।
ক্যাফে

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

3
@EricJ। আপনি কল না করা পর্যন্ত VirtualProtect, যা আপনাকে ডেটা অঞ্চলগুলিকে এক্সিকিউটেবল হিসাবে চিহ্নিত করতে দেয়।
ডায়েটারিচ এপ্পি

37

কিছু কম্পিউটারের কোড এবং ডেটার জন্য পৃথক ঠিকানার স্থান (ছিল)। যেমন হার্ডওয়্যার এটি ঠিক কাজ করে না।

ভাষাটি কেবলমাত্র বর্তমান ডেস্কটপ অ্যাপ্লিকেশনগুলির জন্যই তৈরি করা হয়নি, তবে এটি হার্ডওয়ারের একটি বড় সংখ্যায় প্রয়োগ করা যেতে পারে।


দেখে মনে হচ্ছে সি ভাষা কমিটি কখনই কাজ করার void*জন্য নির্দেশক হতে চায়নি, তারা কেবল বস্তুর প্রতি জেনেরিক পয়েন্টার চেয়েছিল।

সি 99 রেশনেল বলেছেন:

.3.৩.২.৩ পয়েন্টার
সি এখন বিস্তৃত আর্কিটেকচারে প্রয়োগ করা হয়েছে। এর মধ্যে কয়েকটি আর্কিটেকচারে ইউনিফর্ম পয়েন্টার রয়েছে যা কিছু পূর্ণসংখ্যার ধরণের আকারের আকার ধারণ করে, সর্বাধিক বহনযোগ্য কোড বিভিন্ন পয়েন্টার ধরণের এবং পূর্ণসংখ্যার প্রকারের মধ্যে কোনও প্রয়োজনীয় চিঠিপত্র ধরে নিতে পারে না। কিছু বাস্তবায়নের ক্ষেত্রে পয়েন্টারগুলি কোনও সংখ্যার ধরণের চেয়েও বিস্তৃত হতে পারে।

জেনেরিক অবজেক্ট পয়েন্টার টাইপ হিসাবে void*("পয়েন্টার টু void") ব্যবহার করা C89 কমিটির উদ্ভাবন। এই ধরণের গ্রহণটি ফাংশন প্রোটোটাইপ আর্গুমেন্টগুলি নির্দিষ্ট করে দেওয়ার ইচ্ছায় উদ্দীপিত হয়েছিল যা হয় নিঃশব্দে স্বেচ্ছাচারিত পয়েন্টারগুলিকে রূপান্তর করে (হিসাবে হিসাবে fread) বা যুক্তির ধরণটি ঠিক তেমন মেলে না তবে অভিযোগ করুন (হিসাবে হিসাবে strcmp)। ফাংশনগুলির পয়েন্টার সম্পর্কে কিছুই বলা হয় না, যা অবজেক্ট পয়েন্টার এবং / অথবা পূর্ণসংখ্যার সাথে অসম্পূর্ণ হতে পারে।

দ্রষ্টব্য শেষ অনুচ্ছেদে কার্যকারিতা সম্পর্কিত কিছু বলা হয়নি about তারা অন্যান্য পয়েন্টার থেকে পৃথক হতে পারে, এবং কমিটি এটি সম্পর্কে অবগত।


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

15
@ ক্রাজিএডি আপনি একটিতে ফাংশন পয়েন্টার বরাদ্দ করতে পারবেন না void *
ohah

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

5
তবে sizeof(void*) == sizeof( void(*)() )ফাংশন পয়েন্টার এবং ডেটা পয়েন্টারগুলি বিভিন্ন আকারের ক্ষেত্রে প্রয়োজনীয় স্থানটি নষ্ট করবে। এটি 80 এর দশকে একটি সাধারণ ঘটনা ছিল, যখন প্রথম সি স্ট্যান্ডার্ডটি লেখা হয়েছিল।
রবি

8
@RichardChambers: বিভিন্ন অ্যাড্রেস স্পেস এছাড়াও ভিন্ন ঠিকানা থাকতে পারে প্রস্থ যেমন একটি হিসাবে, Atmel এভিআর যে ব্যবহারসমূহ নির্দেশাবলীর জন্য 16 বিট এবং ডেটার জন্য 8 বিট; সেক্ষেত্রে এটি ডেটা (8 বিট) থেকে ফাংশন (16 বিট) পয়েন্টারে এবং আবার ফিরে রূপান্তর করা শক্ত হবে। সি এর প্রয়োগ করা সহজ হবে বলে মনে করা হয়; এই আরামের অংশটি ডেটা এবং নির্দেশের পয়েন্টারগুলিকে একে অপরের সাথে বেমানান রেখেই আসে।
জন বোদে

30

যারা এমএস-ডস, উইন্ডোজ ৩.১ এবং তার চেয়ে বেশি বয়স্কদের মনে রাখবেন তাদের পক্ষে উত্তরটি বেশ সহজ। এই সমস্ত কোড এবং ডেটা পয়েন্টারগুলির জন্য বৈশিষ্ট্যগুলির বিভিন্ন সংমিশ্রণ সহ বিভিন্ন মেমরির বিভিন্ন মডেল সমর্থন করে।

সুতরাং কমপ্যাক্ট মডেলটির উদাহরণস্বরূপ (ছোট কোড, বড় ডেটা):

sizeof(void *) > sizeof(void(*)())

এবং বিপরীতভাবে মাঝারি মডেল (বড় কোড, ছোট ডেটা):

sizeof(void *) < sizeof(void(*)())

এই ক্ষেত্রে আপনার কাছে কোড এবং তারিখের জন্য পৃথক স্টোরেজ নেই তবে এখনও দুটি পয়েন্টারের মধ্যে রূপান্তর করতে পারেন না (অ-স্ট্যান্ডার্ড __্নার এবং __far সংশোধক ব্যবহারের সংক্ষিপ্ততা)।

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


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

4
@ruakh: রূপান্তর যদি int *করতে void *, void *অন্তত বিন্দু একই বস্তুর হিসেবে মূল নিশ্চিত করা হয় int *নি - তাই এই জেনেরিক আলগোরিদিম জন্য দরকারী এই অ্যাক্সেসের সরু-টু বস্তু, মত int n; memcpy(&n, src, sizeof n);। যদি কোনও ফাংশন পয়েন্টারকে রূপান্তর করে ফাংশনটির দিকে নির্দেশকারী পয়েন্টার void *দেয় না, তবে এ জাতীয় অ্যালগরিদমের পক্ষে কার্যকর হয় না - কেবলমাত্র আপনি যা করতে পারেন তা void *আবার ফাংশন পয়েন্টারে ফিরে রূপান্তর করা, যাতে আপনি সম্ভবত ভাল কেবল unionএকটি void *এবং ফাংশন পয়েন্টারযুক্ত একটি ব্যবহার করুন ।
ক্যাফে

@ ক্যাফ: যথেষ্ট ফর্সা। যে ইশারা জন্য ধন্যবাদ। এবং যে বিষয়টি জন্য, এমনকি যদি void* করেনি ফাংশন বিন্দু, আমি এটা জনগণের কাছে এটা পাস করার জন্য একটি খারাপ ধারণা হবে অনুমান করা memcpy। :
পি

উপরে থেকে অনুলিপি করা হয়েছে : পসিক্স ডেটা টাইপগুলিতেvoidvoid *void *
জোনাথন লেফলার

@ কেএফ যদি এটি কেবলমাত্র কিছু কলব্যাকের মধ্য দিয়ে যেতে হবে যা যথাযথ প্রকারটি জানে , আমি কেবল রাউন্ড-ট্রিপ সুরক্ষায় আগ্রহী, রূপান্তরিত মানগুলির সাথে অন্য কোনও সম্পর্ক নয় not
হস্তান্তরকারী

23

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


1
তবে তারপরে dlsym () ফাংশনটি শূন্য * ব্যতীত অন্য কোনও কিছু ফিরিয়ে দেওয়া উচিত নয়। মানে, যদি অকার্যকর * যদি ফাংশন পয়েন্টারটির জন্য যথেষ্ট পরিমাণে বড় না হয় তবে আমরা কি ইতিমধ্যে ফুবরে নেই?
মানব

1
@ কনিকেরিকিকার: হ্যাঁ, সম্ভবত যদি মেমরিটি পরিবেশন করে, dlsym থেকে রিটার্নের ধরণটি ওপেনগ্রুপের ইমেল তালিকায় সম্ভবত 9 বা 10 বছর আগে দীর্ঘ আলোচনা করা হয়েছিল। অফহ্যান্ড, যদিও এর কিছু (যদি কিছু) আসে তবে আমার মনে নেই।
জেরি কফিন

1
তুমি ঠিক বলছো. এটি আপনার পয়েন্টটির মোটামুটি সুন্দর (যদিও পুরানো) সংক্ষিপ্তসার বলে মনে হচ্ছে।
মানব


2
@ লেগোস্টোরমাট্রোপ্র: আকর্ষণীয় যে 21 জন কীভাবে আপ-ভোটিংয়ের ধারণার সাথে একমত হন , তবে প্রায় 3 জনই বাস্তবে এটি করেছেন। :-)
জেরি কফিন

13

এখানে ইতিমধ্যে যা বলা হয়েছে তা ছাড়াও পসিক্সের দিকে নজর দেওয়া আকর্ষণীয় dlsym():

আইএসও সি স্ট্যান্ডার্ডের প্রয়োজন হয় না যে ফাংশনগুলিতে পয়েন্টারগুলি ডেটারে পয়েন্টারগুলিকে পিছনে পিছনে ফেলে দেওয়া যেতে পারে। আসলে, আইএসও সি স্ট্যান্ডার্ডের প্রয়োজন হয় না যে শূন্য * প্রকারের কোনও বস্তু কোনও ফাংশনে একটি পয়েন্টার ধরে রাখতে পারে। এক্সএসআই এক্সটেনশনকে সমর্থনকারী বাস্তবায়নগুলি অবশ্য প্রয়োজন হয় যে শূন্য * টাইপের কোনও অবজেক্ট কোনও ফাংশনে পয়েন্টার ধরে রাখতে পারে। পয়েন্টারটিকে কোনও ফাংশনে পয়েন্টারকে অন্য ডেটা টাইপের (অকার্যকর * বাদে) রূপান্তর করার ফলাফলটি এখনও অপরিজ্ঞাত ined নোট করুন যে আইএসও সি স্ট্যান্ডার্ড অনুসারে সংযোজকগণ যদি একটি শূন্য * পয়েন্টার থেকে ফাংশন পয়েন্টারে রূপান্তরকরণ হিসাবে চেষ্টা করা হয় তবে একটি সতর্কতা তৈরি করতে হবে:

 fptr = (int (*)(int))dlsym(handle, "my_function");

এখানে উল্লিখিত সমস্যার কারণে, ভবিষ্যতের সংস্করণটি হয় ফাংশন পয়েন্টারগুলি ফেরত দিতে একটি নতুন ফাংশন যুক্ত করতে পারে, বা বর্তমান ইন্টারফেসটি দুটি নতুন ফাংশনের পক্ষে অবহেলা করা যেতে পারে: একটি যা ডাটা পয়েন্টারগুলি দেয় এবং অন্যটি ফাংশন পয়েন্টারগুলি ফেরত দেয়।


এর অর্থ কী যে কোনও ফাংশনের ঠিকানা পেতে dlsym ব্যবহার করা বর্তমানে নিরাপদ? এটি করার কোনও নিরাপদ উপায় কি বর্তমানে আছে?
জিক্সিকাইড

4
এর অর্থ বর্তমানে পসিক্সের জন্য এআইবিআই প্ল্যাটফর্মের প্রয়োজন যা ফাংশন এবং ডেটা পয়েন্টার উভয়ই নিরাপদে void*এবং পিছনে ফেলে দেওয়া যেতে পারে ।
ম্যাক্সিম এগারুশকিন

@ জ্যাক্সাইডাইড এর অর্থ হ'ল পসিক্সের অনুগামী যে বাস্তবায়নগুলি মানকে অন্তর্নিহিত আচরণের জন্য একটি বাস্তবায়ন-সংজ্ঞায়িত অর্থ প্রদান করে, ভাষায় একটি প্রসারিত করে। এটি এমনকি সি 99 স্ট্যান্ডার্ড, বিভাগ J.5.7 ফাংশন পয়েন্টার ক্যাস্টারে সাধারণ এক্সটেনশনের একটি হিসাবে তালিকাভুক্ত।
ডেভিড হ্যামেন

1
@ ডেভিডহ্যামেন এটি ভাষার কোনও এক্সটেনশন নয়, বরং নতুন অতিরিক্ত প্রয়োজনীয়তা। সি কোনও void*ফাংশন পয়েন্টারের সাথে সামঞ্জস্য হওয়ার প্রয়োজন হয় না , যেখানে পসিক্স।
ম্যাক্সিম এগারুশকিন

9

C ++ 11 এর সাথে C / C ++ এবং POSIX এর মধ্যে দীর্ঘস্থায়ী অমিলের সমাধান রয়েছে dlsym()reinterpret_castযেহেতু বাস্তবায়ন এই বৈশিষ্ট্যটিকে সমর্থন করে ততক্ষণ একটি ডেটা পয়েন্টার / থেকে কোনও ফাংশন পয়েন্টারকে রূপান্তর করতে ব্যবহার করতে পারে ।

মান থেকে, 5.2.10 প্যারা। 8, "কোনও ফাংশন পয়েন্টারকে কোনও অবজেক্ট পয়েন্টার টাইপ বা তদ্বিপরীত রূপান্তর করা শর্তসাপেক্ষে সমর্থিত।" 1.3.5 "শর্তাধীন-সমর্থিত" কে "প্রোগ্রাম কনস্ট্রাক্ট হিসাবে সংজ্ঞায়িত করে যে বাস্তবায়নের জন্য সমর্থন প্রয়োজন হয় না"।


এক পারে, কিন্তু একজনের উচিত নয়। একটি সংমিশ্রণকারী সংকলক অবশ্যই তার জন্য একটি সতর্কতা তৈরি করতে হবে (যার ফলস্বরূপ কোনও ত্রুটি ট্রিগার করা উচিত, সিএফ। -Werror)। একটি ভাল (এবং নন-ইউবি) সমাধান হ'ল (যেমন ) দ্বারা প্রত্যাবর্তিত বস্তুর কাছে পয়েন্টারটি পুনরুদ্ধার করা এবং এটি একটি পয়েন্টারে ফাংশন পয়েন্টারে রূপান্তর করা । এখনও বাস্তবায়ন-সংজ্ঞায়িত কিন্তু সতর্কতা / ত্রুটির কারণ আর নেইdlsymvoid**
কনরাড রুডল্ফ

3
@ কনরাডরুডল্ফ: অসম্মতি। "শর্তসাপেক্ষে সমর্থিত" শব্দটি বিশেষভাবে কোনও সতর্কতা ছাড়াই সংকলন করার অনুমতি dlsymএবং লেখার জন্য লেখা হয়েছিল GetProcAddress
এমসাল্টারস 11:25

@ এসএমএলটার্স আপনার কি অর্থ, "অসমত"? হয় আমি সঠিক না ভুল। Dlsym ডকুমেন্টেশন স্পষ্টভাবে বলেছেন যে, "আইএসও সি মান অনুসারী কম্পাইলার যদি একটি ফাংশন পয়েন্টার করার জন্য একটি অকার্যকর * পয়েন্টার থেকে একটি রূপান্তর চেষ্টা করা হয় একটি সতর্কবার্তা উৎপন্ন করার প্রয়োজন হয়"। এটি অনুমানের জন্য খুব বেশি জায়গা ছাড়বে না। এবং জিসিসি (সহ -pedantic) সতর্ক করে দেয়। আবার, কোন জল্পনা সম্ভব।
কনরাড রুডল্ফ

1
ফলোআপ: আমার মনে হয় এখন আমি বুঝতে পেরেছি। এটি ইউবি নয় এটি বাস্তবায়ন সংজ্ঞায়িত। আমি এখনও নিশ্চিত নই যে সতর্কতা অবশ্যই উত্পন্ন করা উচিত কিনা - সম্ভবত না। আচ্ছা ভালো.
কনরাড রুডল্ফ

2
@ কনরাড রুডল্ফ: আমি আপনার "উচিত নয়" এর সাথে একমত নই, এটি একটি মতামত। উত্তরে বিশেষত সি ++ 11 উল্লেখ করা হয়েছিল, এবং আমি যখন এই সমস্যাটি সম্বোধন করা হয়েছিল তখন আমি সি ++ সিডাব্লুজি-র সদস্য ছিলাম। C99 এর প্রকৃতপক্ষে আলাদা আলাদা শব্দ রয়েছে, শর্তসাপেক্ষে সমর্থিত একটি সি ++ আবিষ্কার।
এমসাল্টারস 11:58

7

লক্ষ্য আর্কিটেকচারের উপর নির্ভর করে কোড এবং ডেটা মেমরির মূলত বেমানান, শারীরিকভাবে স্বতন্ত্র ক্ষেত্রে সংরক্ষণ করা যেতে পারে।


'শারীরিকভাবে স্বতন্ত্র' আমি বুঝতে পারি, তবে আপনি 'মৌলিকভাবে বেমানান' পার্থক্যটি আরও বিস্তারিতভাবে বর্ণনা করতে পারেন। আমি যেমন প্রশ্নে বলেছি, কোনও পয়েন্টার টাইপের মতো বৃহত্তর মনে করা শূন্য পয়েন্টার নয় - বা এটি আমার পক্ষে একটি ভুল অনুমান।
মানব

@ কেনিকার কিকার: void *কোনও ডেটা পয়েন্টার ধরে রাখতে যথেষ্ট বড়, তবে প্রয়োজনীয় কোনও ফাংশন পয়েন্টার নয়।
প্রথম

1
ভবিষ্যতে ফিরে: পি
এসএসপোক

5

অপরিবর্তিত অগত্যা অনুমোদিত হওয়ার অনুমতি নেই, এটির অর্থ এই হতে পারে যে সংকলক প্রয়োগকারীকে তারা কীভাবে এটি করতে পারে তার আরও স্বাধীনতা আছে।

উদাহরণস্বরূপ এটি কিছু আর্কিটেকচারে সম্ভব নাও হতে পারে - অপরিজ্ঞাত তাদের এখনও একটি 'সি' গ্রন্থাগার রাখতে দেয় এমনকি আপনি এটি না করতে পারলেও।


5

আরেকটি সমাধান:

POSIX একই আকার এবং উপস্থাপনের জন্য ফাংশন এবং ডেটা পয়েন্টারগুলিকে গ্যারান্টি দেয় (এটির জন্য আমি পাঠ্যটি পাই না, তবে ওপি উদ্ধৃত উদাহরণ থেকে বোঝা যায় যে তারা কমপক্ষে এই প্রয়োজনীয়তাটি তৈরি করার উদ্দেশ্যে নিয়েছিল ), নিম্নলিখিতটি কাজ করা উচিত:

double (*cosine)(double);
void *tmp;
handle = dlopen("libm.so", RTLD_LAZY);
tmp = dlsym(handle, "cos");
memcpy(&cosine, &tmp, sizeof cosine);

এটি char []উপস্থাপনের মাধ্যমে অ্যালাইজিং বিধি লঙ্ঘন করা এড়ানো যায় , যা সমস্ত প্রকারের উপামের অনুমতি দেয়।

তবুও অন্য পদ্ধতি:

union {
    double (*fptr)(double);
    void *dptr;
} u;
u.dptr = dlsym(handle, "cos");
cosine = u.fptr;

তবে memcpyআপনি যদি 100% সঠিক সি চান তবে আমি পদ্ধতির পরামর্শ দেব


5

বিভিন্ন স্থানের প্রয়োজনীয়তার সাথে এগুলি বিভিন্ন ধরণের হতে পারে। কাউকে বরাদ্দ করা অপরিবর্তনীয়ভাবে পয়েন্টারের মানকে টুকরো টুকরো করে ফেলতে পারে যাতে ফলাফল নির্ধারণের ফলে অন্যরকম কিছু ঘটে।

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


3

একমাত্র সত্যই পোর্টেবল সমাধান হ'ল dlsymফাংশনগুলির জন্য ব্যবহার না করা , এবং পরিবর্তে dlsymফাংশন পয়েন্টারযুক্ত ডেটারে একটি পয়েন্টার প্রাপ্ত করতে ব্যবহার করা। উদাহরণস্বরূপ, আপনার গ্রন্থাগারে:

struct module foo_module = {
    .create = create_func,
    .destroy = destroy_func,
    .write = write_func,
    /* ... */
};

এবং তারপরে আপনার আবেদনে:

struct module *foo = dlsym(handle, "foo_module");
foo->create(/*...*/);
/* ... */

ঘটনাক্রমে, এটি যাইহোক ভাল নকশা অনুশীলন, এবং dlopenগতিশীল লিঙ্কিং সমর্থন করে না এমন সিস্টেমগুলিতে সমস্ত মডিউলগুলির মাধ্যমে গতিশীল লোডিং এবং স্ট্যাটিক লিঙ্ক উভয়কে সমর্থন করা সহজ করে তোলে বা যেখানে ব্যবহারকারী / সিস্টেম ইন্টিগ্রেটর গতিশীল লিঙ্কিং ব্যবহার করতে চায় না।


2
নিস! যদিও আমি সম্মতি দিচ্ছি এটি আরও রক্ষণাবেক্ষণযোগ্য বলে মনে হচ্ছে, তবে এটি এখনও স্থিতিশীল নয় যে আমি এর উপরে স্থিতিশীল সংযোগে হাতুড়িও কীভাবে রেখেছি। তুমি কি বিস্তারিত বলতে পারো?
মানব

2
যদি প্রতিটি মডিউলের নিজস্ব foo_moduleকাঠামো থাকে (স্বতন্ত্র নাম সহ), আপনি struct { const char *module_name; const struct module *module_funcs; }মডিউলটি "লোড" করতে চান এবং ডান পয়েন্টারটি ফিরিয়ে দিতে চান সেই মডিউলটির জন্য এই টেবিলটি অনুসন্ধান করার জন্য আপনি কেবল একটি অ্যারের এবং একটি সাধারণ ফাংশন সহ একটি অতিরিক্ত ফাইল তৈরি করতে পারেন, তবে এটি ব্যবহার করুন এর জায়গায় dlopenএবং dlsym
আর .. গিথহাব বন্ধ হেল্পিং আইসিসি

@ আর .. সত্য, তবে এটি মডিউল কাঠামো বজায় রেখে রক্ষণাবেক্ষণ ব্যয় যুক্ত করে।
ব্যবহারকারীর 877329

3

ফাংশন পয়েন্টারগুলি যেখানে ডাটা পয়েন্টার থেকে আকারে পৃথক হতে পারে তার একটি আধুনিক উদাহরণ: সি ++ শ্রেণির সদস্য ফাংশন পয়েন্টার

Https://blogs.msdn.microsoft.com/oldnewthing/20040209-00/?p=40713/ থেকে সরাসরি উদ্ধৃত

class Base1 { int b1; void Base1Method(); };
class Base2 { int b2; void Base2Method(); };
class Derived : public Base1, Base2 { int d; void DerivedMethod(); };

এখন দুটি সম্ভাব্য thisপয়েন্টার রয়েছে।

এর সদস্য ফাংশনের Base1একটি পয়েন্টার একটি সদস্য ফাংশনের পয়েন্টার হিসাবে ব্যবহার করা যেতে পারে Derived, যেহেতু তারা উভয়ই একই this পয়েন্টার ব্যবহার করে । কিন্তু একজন সদস্য ফাংশন একটি পয়েন্টার Base2ব্যবহার করা যাবে না একজন সদস্য ফাংশন একটি পয়েন্টার হিসাবে হিসাবে হয় Derived, যেহেতু this পয়েন্টার চাহিদা স্থায়ী করা হবে।

এটি সমাধান করার বিভিন্ন উপায় রয়েছে। ভিজ্যুয়াল স্টুডিও সংকলক কীভাবে এটি পরিচালনা করবেন তা এখানে দেখুন:

একটি বহুগুণ-উত্তরাধিকারী শ্রেণীর সদস্য ফাংশনের একটি পয়েন্টার সত্যই একটি কাঠামো।

[Address of function]
[Adjustor]

একাধিক উত্তরাধিকার ব্যবহার করে এমন শ্রেণীর পয়েন্টার-টু-সদস্য-ফাংশনের আকার পয়েন্টারের আকার এবং এর আকার size_t

tl; dr: একাধিক উত্তরাধিকার ব্যবহার করার সময়, সদস্য ফাংশনের একটি পয়েন্টার (সংকলক, সংস্করণ, আর্কিটেকচার ইত্যাদির উপর নির্ভর করে) আসলে হিসাবে সংরক্ষণ করা যেতে পারে

struct { 
    void * func;
    size_t offset;
}

যা স্পষ্টতই একটি এর চেয়ে বড় void *


2

বেশিরভাগ আর্কিটেকচারে, সমস্ত সাধারণ ডেটা টাইপের দিকে পয়েন্টারগুলির উপস্থাপনা একই থাকে, তাই ডেটা পয়েন্টার ধরণের মধ্যে কাস্টিং একটি অনিঃপত্তি।

যাইহোক, এটি অনুমেয় যে ফাংশন পয়েন্টারগুলির জন্য আলাদা উপস্থাপনের প্রয়োজন হতে পারে, সম্ভবত তারা অন্যান্য পয়েন্টারের চেয়ে বড়। যদি শূন্য * ফাংশন পয়েন্টার ধরে রাখতে পারে তবে এর অর্থ হ'ল শূন্য * এর প্রতিনিধিত্ব বৃহত্তর আকার হতে হবে। এবং অকার্যকর * থেকে / ডেটা পয়েন্টারগুলির সমস্ত ক্যাসকে এই অতিরিক্ত অনুলিপিটি সম্পাদন করতে হবে।

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


-1

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


এই উত্তরটি ভুল। আপনি উদাহরণস্বরূপ কোনও ফাংশন পয়েন্টারকে ডেটা পয়েন্টারে রূপান্তর করতে এবং এটি থেকে পড়তে পারেন (যদি আপনার ঠিক আগের মত ঠিকানা থেকে পড়ার অনুমতি থাকে)। ফলাফলটি যতটা বোঝায় ততই বোঝায় যেমন x86 এ।
ম্যানুয়েল জ্যাকব
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.