উত্তর:
সহজ উত্তর, ধরে নিলে আপনি বিভিন্ন প্ল্যাটফর্মের মধ্যে বিন্যাসে ভোজন এবং ভিন্নতাগুলিকে কিছু মনে করেন না এটি হ'ল মানক %p
স্বীকৃতি।
সি 99 স্ট্যান্ডার্ড (আইএসও / আইইসি 9899: 1999) §7.19.6.1 ¶8 এ বলেছেন:
p
যুক্তি একটি পয়েন্টার হতে হবেvoid
। নির্দেশকের মান প্রয়োগকরণ-সংজ্ঞায়িত পদ্ধতিতে মুদ্রণ অক্ষরের ক্রমতে রূপান্তরিত হয়।
(সি 11 - আইএসও / আইইসি 9899: 2011 - তথ্যটি §7.21.6.1 ¶8 এ রয়েছে))
কিছু প্ল্যাটফর্মে, এর মধ্যে একটি শীর্ষস্থানীয় অন্তর্ভুক্ত থাকবে 0x
এবং অন্যের উপর এটি থাকবে না এবং অক্ষরগুলি নিম্ন-ক্ষেত্রে বা উচ্চ-ক্ষেত্রে হতে পারে এবং সি স্ট্যান্ডার্ড এমনকি এটি নির্ধারণ করে না যে এটি হেক্সাডেসিমাল আউটপুট হবে যদিও আমি জানি বাস্তবায়ন নেই যেখানে এটি নেই।
আপনার বিতর্কটি কিছুটা উন্মুক্ত যাতে আপনার স্পষ্টতই একটি (void *)
কাস্টের সাহায্যে পয়েন্টারগুলি রূপান্তর করা উচিত । এটি সুস্পষ্টভাবে প্রকাশ করা হচ্ছে, যা সাধারণত ভাল হয় (তাই এটি আমি যা করি তা), এবং মানকটি বলে যে 'যুক্তিটি পয়েন্টার হবে। void
' বেশিরভাগ মেশিনে, আপনি একটি সুস্পষ্ট কাস্ট বাদ দিয়ে চলে যাবেন। তবে এটি এমন কোনও মেশিনের ক্ষেত্রে বিবেচিত হবে যেখানে char *
প্রদত্ত মেমরির অবস্থানের জন্য ঠিকানার কোনও বিট উপস্থাপনা একই মেমরির অবস্থানের জন্য ' অন্য কিছু পয়েন্টার ' ঠিকানার থেকে পৃথক। এটি একটি শব্দ-সম্বোধন হবে, বাইট-অ্যাড্রেসড, মেশিনের পরিবর্তে। এই জাতীয় মেশিনগুলি আজকাল সাধারণ নয় (সম্ভবত উপলভ্য নয়) তবে আমি বিশ্ববিদ্যালয়ের পরে প্রথম যে মেশিনে কাজ করেছি সেগুলিই ছিল (আইসিএল পার্ক)।
আপনি যদি বাস্তবায়ন-সংজ্ঞায়িত আচরণের সাথে সন্তুষ্ট না হন %p
তবে C99 <inttypes.h>
এবং এর uintptr_t
পরিবর্তে ব্যবহার করুন:
printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);
এটি আপনাকে নিজের অনুসারে উপস্থাপনাটি সূক্ষ্ম-টিউন করতে দেয় to আমি উচ্চতর ক্ষেত্রে হেক্স অঙ্কগুলি বেছে নিয়েছি যাতে সংখ্যাটি সমানভাবে একই উচ্চতা হয় এবং শুরুতে বৈশিষ্ট্যপূর্ণ 0xA1B2CDEF
ডিপটি এভাবে প্রকাশ পায়, তবে 0xa1b2cdef
এটির মতো নয় যে সংখ্যাটি বরাবরও নীচে নেমে যায়। আপনার পছন্দ যদিও, খুব বিস্তৃত সীমাবদ্ধতা মধ্যে। (uintptr_t)
ঢালাই unambiguously জিসিসি দ্বারা বাঞ্ছনীয় যখন এটা কম্পাইল সময়ে ফরম্যাট স্ট্রিং পড়তে পারেন। আমি মনে করি অভিনেতাদের অনুরোধ করা ঠিক হবে, যদিও আমি নিশ্চিত যে এমন কিছু লোক আছেন যারা সতর্কতাটিকে উপেক্ষা করবেন এবং বেশিরভাগ সময় এটি থেকে দূরে সরে যাবেন।
কেরেক মন্তব্যগুলিতে জিজ্ঞাসা করেছেন:
আমি স্ট্যান্ডার্ড প্রচার এবং বৈকল্পিক যুক্তি সম্পর্কে কিছুটা বিভ্রান্ত। সমস্ত পয়েন্টার কি শূন্য * স্ট্যান্ডার্ড-প্রচারিত হয়? অন্যথায়, যদি
int*
বলি, দুটি বাইট, এবংvoid*
4 বাইট ছিল, তবে এটি স্পষ্টতই তর্ক থেকে চারটি বাইট পড়তে ভুল হবে, না?
আমি এই মায়ার মধ্যে ছিলাম যে সি স্ট্যান্ডার্ড বলেছে যে সমস্ত অবজেক্ট পয়েন্টারগুলি অবশ্যই একই আকারের হবে, তাই void *
এবং int *
বিভিন্ন আকার হতে পারে না। যাইহোক, আমি যা মনে করি C99 স্ট্যান্ডার্ডের প্রাসঙ্গিক বিভাগটি তেমন জোরালো নয় (যদিও আমি এমন কোনও বাস্তবায়ন সম্পর্কে জানিনা যেখানে আমি প্রস্তাবিত সত্যটি সত্য মিথ্যা):
.6.2.5 প্রকার
¶26 অকার্যকর করার জন্য একটি পয়েন্টারের একটি চরিত্রের ধরণের পয়েন্টার হিসাবে একই উপস্থাপনা এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে। 39) একইভাবে, সামঞ্জস্যপূর্ণ প্রকারের যোগ্য বা অযোগ্য সংস্করণের পয়েন্টারগুলির একই উপস্থাপনা এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে। কাঠামোর ধরণের সমস্ত পয়েন্টারের একে অপরের মতো প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে। ইউনিয়নের ধরণের সমস্ত পয়েন্টারগুলির একে অপরের মতো প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে। অন্যান্য ধরণের পয়েন্টারগুলির একই প্রতিনিধিত্ব বা প্রান্তিককরণের প্রয়োজনীয়তা থাকা দরকার না।
39) একই প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তাগুলি হ'ল ফাংশনগুলিতে আর্গুমেন্ট, ফাংশন থেকে মানগুলি ফেরত দেওয়া এবং ইউনিয়নের সদস্য হিসাবে আদান প্রদানের বোঝা।
(সি 11 §6.2.5, ¶28 বিভাগ এবং পাদটীকা 48 এ ঠিক একই কথা বলেছে।)
সুতরাং, কাঠামোগুলির সমস্ত পয়েন্টার অবশ্যই একে অপরের মতো সমান আকারের হওয়া উচিত এবং একই প্রান্তিককরণের প্রয়োজনীয়তাগুলি অবশ্যই ভাগ করতে হবে, যদিও বিন্দুগুলির বিন্দুগুলির কাঠামোগুলির বিভিন্ন প্রান্তিককরণের প্রয়োজনীয়তা থাকতে পারে। একইভাবে ইউনিয়নগুলির জন্য। ক্যারেক্টার পয়েন্টার এবং অকার্যকর পয়েন্টারগুলির অবশ্যই একই আকার এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে। পরিবর্তনের জন্য পয়েন্টারগুলির int
(অর্থ unsigned int
এবং signed int
) একে অপরের মতো একই আকার এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে; একইভাবে অন্যান্য ধরণের জন্য। তবে সি স্ট্যান্ডার্ড আনুষ্ঠানিকভাবে এটি বলে না sizeof(int *) == sizeof(void *)
। ওহ ভাল, আপনাকে আপনার অনুমানগুলি পরিদর্শন করার জন্য তাই ভাল।
সি স্ট্যান্ডার্ডের অবশ্যই অবজেক্ট পয়েন্টারগুলির মতো একই আকারের ফাংশন পয়েন্টারগুলির প্রয়োজন হয় না। ডস-এর মতো সিস্টেমে বিভিন্ন মেমরির মডেলগুলি না ভাঙার জন্য এটি প্রয়োজনীয় ছিল। সেখানে আপনার কাছে 16-বিট ডেটা পয়েন্টার থাকতে পারে তবে 32-বিট ফাংশন পয়েন্টার বা বিপরীতে। এই কারণেই সি স্ট্যান্ডার্ড আদেশ দেয় না যে ফাংশন পয়েন্টারগুলি বস্তু পয়েন্টারগুলিতে রূপান্তর করতে পারে এবং বিপরীতে।
ভাগ্যক্রমে (প্রোগ্রামারদের জন্য পসিক্স লক্ষ্য করে), পসিক্স লঙ্ঘনের পদক্ষেপ নেয় এবং ফাংশন পয়েন্টার এবং ডেটা পয়েন্টারগুলি একই আকারের নির্দেশ দেয়:
.2.12.3 পয়েন্টার প্রকার
সমস্ত ফাংশন পয়েন্টার প্রকারের শূন্যস্থান বিন্দু টাইপের অনুরূপ প্রতিনিধিত্ব করতে হবে। কোনও ক্রিয়াকলাপের পয়েন্টারের রূপান্তর
void *
উপস্থাপনাটিকে পরিবর্তন করে না। এvoid *
জাতীয় রূপান্তরকরণের ফলে প্রাপ্ত মানটি কোনও তথ্য ক্ষতি ছাড়াই একটি সুস্পষ্ট castালাই ব্যবহার করে মূল ফাংশন পয়েন্টার টাইপে ফিরে রূপান্তরিত হতে পারে।দ্রষ্টব্য: আইএসও সি স্ট্যান্ডার্ডটির এটির প্রয়োজন নেই, তবে এটি পসিক্স কনফারেন্সের জন্য প্রয়োজন।
সুতরাং, দেখে মনে হচ্ছে যে স্পষ্ট void *
ক্যাসেটগুলি কোডটিতে সর্বাধিক নির্ভরযোগ্যতার জন্য দৃ strongly়ভাবে পরামর্শ দেওয়া হয় যেমন কোনও বৈকল্পিক ফাংশনে একটি পয়েন্টার পাস করার সময় printf()
। পসিক্স সিস্টেমে মুদ্রণের জন্য একটি ফাংশন পয়েন্টারটি একটি শূন্য পয়েন্টারটিতে কাস্ট করা নিরাপদ। অন্যান্য সিস্টেমে এটি করা অপরিহার্যভাবে নিরাপদ নয় এবং void *
a ালাই ব্যতীত অন্য পয়েন্টারগুলি পাস করাও প্রয়োজনীয় নয় ।
dlsym()
পরিবর্তে ফাংশনে সরিয়ে নিয়েছে। একদিন আমি পরিবর্তনটি লিখব ... তবে 'একদিন' 'আজ' নয়।
void *
কোনও তথ্য ক্ষতি ছাড়াই একটি এবং পিছনে রূপান্তর করতে পারে । ব্যবহারিকভাবে, খুব কম মেশিন রয়েছে যেখানে কোনও ফাংশন পয়েন্টারের আকার কোনও অবজেক্ট পয়েন্টারের আকারের মতো হয় না। আমি মনে করি না যে স্ট্যান্ডার্ডটি এমন মেশিনগুলিতে ফাংশন পয়েন্টার মুদ্রণের একটি পদ্ধতি সরবরাহ করে যেখানে থা রূপান্তর সমস্যাযুক্ত।
p
পয়েন্টার মুদ্রণের জন্য রূপান্তর নির্দিষ্টকরণকারী। এটা ব্যবহার কর.
int a = 42;
printf("%p\n", (void *) &a);
মনে রাখবেন theালাই বাদ দেওয়া অনির্ধারিত আচরণ এবং p
রূপান্তর নির্দিষ্টকারীর সাথে মুদ্রণটি একটি বাস্তবায়ন-সংজ্ঞায়িত পদ্ধতিতে সম্পন্ন হয়।
%p
"পয়েন্টার" এর জন্য ব্যবহার করুন এবং অন্য কিছু ব্যবহার করবেন না *। আপনাকে কোনও নির্দিষ্ট ধরণের পূর্ণসংখ্যার মতো পয়েন্টারের সাথে আচরণ করার অনুমতি দেওয়া হয়েছে এমন মানদণ্ডের দ্বারা আপনাকে গ্যারান্টিযুক্ত করা যায় না, সুতরাং আপনি অবিচ্ছেদ্য ফর্ম্যাটগুলির সাথে প্রকৃতপক্ষে অপরিবর্তিত আচরণ পাবেন। (উদাহরণস্বরূপ, %u
একটি প্রত্যাশা করে unsigned int
তবে তার void*
চেয়ে আলাদা আকার বা প্রান্তিককরণের প্রয়োজন থাকলে কী হবে unsigned int
?)
*) [জোনাথনের সূক্ষ্ম উত্তর দেখুন!] বিকল্প হিসাবে %p
, আপনি সি 99-এ যুক্ত পয়েন্টার-নির্দিষ্ট ম্যাক্রোগুলি ব্যবহার করতে পারেন <inttypes.h>
।
সমস্ত অবজেক্ট পয়েন্টারগুলি void*
স্পষ্টত সি তে রূপান্তরিত হয় , তবে পয়েন্টারটিকে বৈকল্পিক আর্গুমেন্ট হিসাবে পাস করার জন্য আপনাকে এটিকে স্পষ্টতই কাস্ট করতে হয় (যেহেতু স্বেচ্ছাচারিতা অবজেক্ট পয়েন্টারগুলি কেবল রূপান্তরযোগ্য তবে অকার্যকর পয়েন্টারগুলির অনুরূপ নয় ):
printf("x lives at %p.\n", (void*)&x);
void *
(যদিও আপনার জন্য printf()
প্রযুক্তিগতভাবে স্পষ্ট কাস্টের প্রয়োজন, যেহেতু এটি একটি বৈকল্পিক ফাংশন)। ফাংশন পয়েন্টারগুলি অগত্যা রূপান্তরিত হয় না void *
।
void *
ফাংশন পয়েন্টারগুলি বিনা পরিবর্তে ফাংশন পয়েন্টারে রূপান্তরিত হয় এবং ফিরে যেতে পারে; সৌভাগ্যক্রমে, যদিও, পসিক্সের স্পষ্টরূপে এটির প্রয়োজন হয় (এটি লক্ষ্য করা যায় যে এটি স্ট্যান্ডার্ড সি এর অংশ নয়)। সুতরাং, অনুশীলনে, আপনি এটি থেকে পালাতে void (*function)(void)
পারেন (রূপান্তর করতে void *
এবং ফিরে যেতে void (*function)(void)
), তবে কঠোরভাবে এটি সি স্ট্যান্ডার্ড দ্বারা বাধ্যতামূলক নয়।
%u
!
%u
এবং সমস্ত মেশিনে%lu
ভুল , কিছু মেশিন নয়। এর স্পেসিফিকেশনটি খুব স্পষ্ট যে প্রকারটি যখন পাস করা হয়েছে তখন ফর্ম্যাট স্পেসিফায়ারের দ্বারা প্রয়োজনীয় ধরণের সাথে মেলে না, আচরণটি অপরিজ্ঞাত। প্রকারের মিলগুলির আকার (যা মেশিনের উপর নির্ভর করে সত্য বা মিথ্যা হতে পারে) অপ্রাসঙ্গিক কিনা; এটি এমন ধরণের যেগুলি অবশ্যই মিলবে এবং তারা কখনই তা মিলবে না। printf
অন্যান্য (খুব ভাল) উত্তরের বিকল্প হিসাবে আপনি কাস্টিং uintptr_t
বা intptr_t
(থেকে stdint.h
/ inttypes.h
) এবং সম্পর্কিত সংখ্যার রূপান্তর স্পেসিফায়ার ব্যবহার করতে পারেন। এটি পয়েন্টারটি কীভাবে ফর্ম্যাট করা যায় তাতে আরও নমনীয়তার সুযোগ দেয়, তবে কঠোরভাবে কোনও প্রয়োগকরণের জন্য এই টাইপিডগুলি সরবরাহ করার প্রয়োজন হয় না।
#include <stdio.h> int main(void) { int p=9; int* m=&s; printf("%u",m); }
ব্যবহার %u
করে ভেরিয়েবলের ঠিকানা মুদ্রণ করা কি এই অপরিবর্তিত আচরণ বিবেচনা করবেন ? বেশিরভাগ ক্ষেত্রে ভেরিয়েবলের ঠিকানা ইতিবাচক হয় তাই আমি কি এর %u
পরিবর্তে ব্যবহার করতে পারি %p
?
%u
এটি unsigned int
টাইপের জন্য একটি ফর্ম্যাট এবং এতে পয়েন্টার যুক্তির সাহায্যে ব্যবহার করা যায় না printf
।
আপনি ব্যবহার করতে পারেন %x
বা %X
বা %p
; তাদের সব ঠিক আছে।
%x
তবে ঠিকানাটি ছোট হাতের হিসাবে দেওয়া হবে, উদাহরণস্বরূপ:a3bfbc4
%X
তবে ঠিকানাটি বড় হাতের হিসাবে দেওয়া হবে, উদাহরণস্বরূপ:A3BFBC4
এই দুটিই সঠিক।
আপনি যদি ব্যবহার করেন %x
বা %X
এটি ঠিকানার জন্য ছয়টি অবস্থান বিবেচনা করছেন এবং আপনি যদি %p
এটি ব্যবহার করেন তবে ঠিকানার জন্য আটটি অবস্থান বিবেচনা করা হবে। উদাহরণ স্বরূপ:
void*
? অন্যথায়, যদিint*
বলি, দুটি বাইট, এবংvoid*
4 বাইট ছিল, তবে এটি স্পষ্টতই তর্ক থেকে চারটি বাইট পড়তে ভুল হবে, না?