সিটিতে তীর (->) অপারেটরটি কেন বিদ্যমান?


264

বিন্দু ( .) অপারেটরটি কোনও কাঠামোর সদস্য অ্যাক্সেস করতে ব্যবহৃত হয়, অন্যদিকে ->সিতে থাকা তীর অপারেটর ( ) ব্যবহারকারীর কাঠামোর সদস্যকে অ্যাক্সেস করতে ব্যবহৃত হয় যা প্রশ্নের পয়েন্টার দ্বারা রেফারেন্স করা হয়।

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

তাহলে ভাষা নির্মাতারা কেন এই আপাতদৃষ্টিতে অপ্রয়োজনীয় অপারেটর যুক্ত করে জিনিসগুলিকে আরও জটিল করার সিদ্ধান্ত নিয়েছে? বড় ডিজাইনের সিদ্ধান্ত কী?


1
সম্পর্কিত: stackoverflow.com/questions/221346/… - এছাড়াও, আপনি ওভাররাইড করতে পারেন ->
ক্রয়েজ

16
@ ক্রিস এটি সম্পর্কে যে সি ++ অবশ্যই অবশ্যই একটি বড় পার্থক্য করে। তবে যেহেতু আমরা কেন সিটিকে এইভাবে ডিজাইন করা হয়েছিল সে সম্পর্কে কথা বলছি , আসুন আমরা ভেবে দেখি যে আমরা 1970 এর দশকে ফিরে এসেছি - সি ++ এর অস্তিত্বের আগে।
রহস্যময়

5
আমার সেরা অনুমান, তীর অপারেটরটি "এটি দেখুন! আপনি এখানে একটি পয়েন্টার নিয়ে কাজ করছেন"
ক্রিস

4
এক নজরে, আমি মনে করি এই প্রশ্নটি খুব অদ্ভুত। সমস্ত জিনিস চিন্তা করে ডিজাইন করা হয় না। আপনি যদি এই স্টাইলটি আপনার পুরো জীবনে রাখেন তবে আপনার বিশ্ব প্রশ্নে ভরা। যে উত্তরটি সবচেয়ে বেশি ভোট পেয়েছে তা সত্যই তথ্যপূর্ণ এবং স্পষ্ট clear তবে এটি আপনার প্রশ্নের মূল বিষয়টিকে আঘাত করে না। আপনার প্রশ্নের স্টাইল অনুসরণ করুন, আমি অনেক বেশি প্রশ্ন জিজ্ঞাসা করতে পারি। উদাহরণস্বরূপ, 'int' মূল শব্দটি হ'ল 'পূর্ণসংখ্যা' এর সংক্ষেপণ; 'ডাবল' কীওয়ার্ডটিও ছোট হবে না কেন?
জুনওয়ানহে

1
@ জুনওয়ানহে এই প্রশ্নটি আসলে বৈধ উদ্বেগের প্রতিনিধিত্ব করে - কেন .অপারেটরের চেয়ে *অপারেটরের চেয়ে বেশি অগ্রাধিকার রয়েছে ? যদি এটি না হয় তবে আমাদের * পিটিআরএমবার এবং ভার্সেমবার থাকতে পারে।
মিলেনিয়ামব্যাগ

উত্তর:


358

আমি আপনার প্রশ্নটিকে দুটি প্রশ্ন হিসাবে ব্যাখ্যা করব: 1) কেন ->উপস্থিত রয়েছে এবং 2) কেন .পয়েন্টারটি স্বয়ংক্রিয়ভাবে অবচয় হয় না। উভয় প্রশ্নের উত্তরের historicalতিহাসিক মূল রয়েছে।

->এমনকি কেন বিদ্যমান?

সি ভাষার প্রথম সংস্করণগুলির মধ্যে একটিতে (যা আমি " সি রেফারেন্স ম্যানুয়াল " এর জন্য সিআরএম হিসাবে উল্লেখ করব , যা ১৯ 197৫ সালের মে মাসে 6th ষ্ঠ সংস্করণ ইউনিক্স নিয়ে এসেছিল), অপারেটরের ->খুব অনন্য অর্থ ছিল, সমার্থক *এবং .সমন্বয় নয়

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

struct S {
  int a;
  int b;
};

এবং নামটি aঅফসেট ০-এর জন্য দাঁড়ায়, আর নামটি bঅফসেট ২-এর জন্য দাঁড়ায় ( intআকারের ধরণ 2 এবং কোনও প্যাডিং না ধরে) would অনুবাদ ইউনিটে সমস্ত স্ট্রাক্টের সমস্ত সদস্যের ভাষাটির প্রয়োজন হয় স্বতন্ত্র নাম অথবা একই অফসেট মানের জন্য দাঁড়ানো। যেমন একই অনুবাদ ইউনিটে আপনি অতিরিক্তভাবে ঘোষণা করতে পারেন

struct X {
  int a;
  int x;
};

এবং এটি ঠিক থাকবে, যেহেতু নামটি aধারাবাহিকভাবে অফসেট 0 এর জন্য দাঁড়াবে But তবে এই অতিরিক্ত ঘোষণা

struct Y {
  int b;
  int a;
};

এটি আনুষ্ঠানিকভাবে অবৈধ হবে, যেহেতু এটি aঅফসেট 2 এবং bঅফসেট 0 হিসাবে "পুনরায় সংজ্ঞায়িত" করার চেষ্টা করেছিল ।

আর এই কোথায় ->অপারেটর আসে। যেহেতু প্রত্যেক struct হয় সদস্য নাম নিজস্ব স্বাবলম্বী বিশ্বব্যাপী অর্থ ছিল, ভাষা সমর্থিত এই মত এক্সপ্রেশন

int i = 5;
i->b = 42;  /* Write 42 into `int` at address 7 */
100->a = 0; /* Write 0 into `int` at address 100 */

প্রথম অ্যাসাইনমেন্ট যেমন কম্পাইলার ব্যাখ্যা করা হয় "নিতে ঠিকানা 5, অফসেট যোগ 2এটি এবং দায়িত্ব অর্পণ করা 42থেকে intপরিসমাপ্তি ঠিকানায় মান"। অর্থাত উপরে দায়িত্ব অর্পণ করবে 42করার intঠিকানায় মান 7। মনে রাখবেন যে এর ব্যবহারটি ->বাম-হাতের অভিব্যক্তির ধরণের বিষয়ে চিন্তা করে না। বাম হাতটি মূল্যের সংখ্যাসূচক ঠিকানা হিসাবে ব্যাখ্যা করা হয়েছে (এটি পয়েন্টার বা একটি পূর্ণসংখ্যা)।

এই ধরণের কৌশল *এবং .সংমিশ্রণ সম্ভব ছিল না । আপনি করতে পারেন না

(*i).b = 42;

যেহেতু *iইতিমধ্যে একটি অবৈধ অভিব্যক্তি। *অপারেটর, যেহেতু এটি থেকে পৃথক .তার প্রতীক উপর, চাপিয়ে আরো কঠোর টাইপ প্রয়োজনীয়তা। এই সীমাবদ্ধতাটি ঘিরে কাজ করার জন্য একটি দক্ষতা সরবরাহ করার জন্য সিআরএম ->অপারেটরটির সাথে পরিচয় করিয়ে দিয়েছিল , যা বাম-হাতের ক্রিয়াকলাপ থেকে পৃথক।

কীথ মন্তব্যগুলিতে উল্লেখ করেছেন, ->এবং *+ .সংমিশ্রণের মধ্যে এই পার্থক্যটি সিআরএম 7.১.৮-তে "প্রয়োজনীয়তার শিথিলকরণ" হিসাবে উল্লেখ করছে: পয়েন্টার ধরণের প্রয়োজনের শিথিলকরণ বাদে E1অভিব্যক্তিটি E1−>MOSঠিক সমান(*E1).MOS

পরে, কেএন্ডআর সিতে মূলত সিআরএম-এ বর্ণিত অনেকগুলি বৈশিষ্ট্য উল্লেখযোগ্যভাবে পুনরায় কাজ করা হয়েছিল। "গ্লোবাল অফসেট শনাক্তকারী হিসাবে স্ট্রাক্ট সদস্যের ধারণা" সম্পূর্ণরূপে সরানো হয়েছে। এবং ->অপারেটরের কার্যকারিতা *এবং .সংমিশ্রণের কার্যকারিতা সম্পূর্ণরূপে অভিন্ন হয়ে উঠেছে ।

.পয়েন্টারটি স্বয়ংক্রিয়ভাবে কেন অবজ্ঞা করতে পারে না ?

আবার, ভাষার সিআরএম সংস্করণে .অপারেটরের বাম অপারেন্ডের একটি লভ্যালু হওয়া দরকার । এই অপারেন্ডে কেবলমাত্র একমাত্র প্রয়োজনীয়তা আরোপ করা হয়েছিল (এবং ->উপরে বর্ণিত হিসাবে এটিই এটিকে আলাদা করেছে )। লক্ষ্য করুন সিআরএম হয়নি না বাম প্রতীক প্রয়োজন .একটি struct টাইপ আছে। এটি কেবল এটি একটি ল্যাভালু, কোনও লভালু হওয়া দরকার। এর অর্থ সি এর সিআরএম সংস্করণে আপনি এই জাতীয় কোড লিখতে পারেন

struct S { int a, b; };
struct T { float x, y, z; };

struct T c;
c.b = 55;

এক্ষেত্রে সংকলকটি অবিচ্ছিন্ন মেমরি ব্লকের বাইট-অফসেট 2 এ অবস্থিত 55একটি intমান হিসাবে লিখবে c, যদিও টাইপের struct Tকোনও ক্ষেত্রের নাম নেই b। সংকলকটি প্রকৃত ধরণের বিষয়ে মোটেই চিন্তা করে না ccএগুলির যত্ন নেওয়া সমস্তটাই হ'ল একটি মূল্যবান: একধরনের লিখনযোগ্য মেমরি ব্লক।

এখন মনে রাখবেন যে আপনি যদি এটি করেন

S *s;
...
s.b = 42;

কোডটি বৈধ হিসাবে বিবেচিত হবে (যেহেতু sএটি একটি লভ্যালুও) এবং সংকলকটি কেবল পয়েন্টারে sনিজেই বাইট-অফসেটে ডেটা লেখার চেষ্টা করবে say বলা বাহুল্য, এই জাতীয় জিনিসগুলি সহজেই স্মৃতিকে ছাপিয়ে যেতে পারে তবে ভাষা এ জাতীয় বিষয় নিয়ে নিজেকে উদ্বিগ্ন করেনি।

অর্থাত্ ভাষাটির সেই সংস্করণে .পয়েন্টার ধরণের জন্য ওভারলোডিং অপারেটর সম্পর্কে আপনার প্রস্তাবিত ধারণাটি কার্যকর হবে না: .পয়েন্টারগুলির সাথে ব্যবহার করার সময় অপারেটরের ইতিমধ্যে খুব সুনির্দিষ্ট অর্থ ছিল (ল্যাভালু পয়েন্টার সহ বা কোনও লভ্যু দিয়ে)। এটি খুব অদ্ভুত কার্যকারিতা ছিল, সন্দেহ নেই। তবে সে সময় সেখানে ছিল।

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

(1975 সি রেফারেন্স ম্যানুয়ালটির URL টি স্থিতিশীল নাও হতে পারে Another সম্ভবত কিছু সূক্ষ্ম পার্থক্য সহ আরও একটি অনুলিপি এখানে রয়েছে ))


10
এবং উদ্ধৃত সি রেফারেন্স ম্যানুয়ালের 7.১.৮ অনুচ্ছেদে বলা হয়েছে "E1 পয়েন্টার ধরণের হওয়া প্রয়োজনের শিথিলতা বাদে '' E1−> এমওএস '' এক্সপ্রেশনটি '' (* E1) এর সমান । "
কিথ থম্পসন

1
কেন এটি 5 *iনাম্বারটিতে কোনও ডিফল্ট টাইপের (ইন্ট?) মূল্য নেই? তারপরে (* i) .b একইভাবে কাজ করবে।
র্যান্ডম 832

5
@ লিও: আচ্ছা, কিছু লোক সি ভাষার উচ্চ স্তরের সমাবেশকারী হিসাবে পছন্দ করে। সি ইতিহাসে সেই সময়কালে ভাষাটি প্রকৃতপক্ষে উচ্চতর স্তরের একত্রিত হয়।
এএনটি

29
হাহ। সুতরাং এটি ব্যাখ্যা করে যে কেন ইউনিক্সে অনেক কাঠামো (যেমন, struct stat) তাদের ক্ষেত্রগুলি (যেমন, st_mode) উপসর্গ করে ।
আইটুফুয়ে

5
@ পারফেকশন এম 1 এং: দেখে মনে হচ্ছে অ্যালকাটেল-লুসেন্ট বেল-ল্যাবস.কমটি নিয়ে গেছে এবং মূল পৃষ্ঠাগুলি চলে গেছে। আমি অন্য সাইটে লিঙ্কটি আপডেট করেছি, যদিও এটি আর কতক্ষণ থাকবে তা আমি বলতে পারি না। যাইহোক, "রিচি সি রেফারেন্স ম্যানুয়াল" এর জন্য গুগলিং সাধারণত নথিটি সন্ধান করে।
এএনটি

46

Historicalতিহাসিক (ভাল এবং ইতিমধ্যে রিপোর্ট করা) কারণগুলি ছাড়াই অপারেটরদের অগ্রাধিকারের ক্ষেত্রেও কিছুটা সমস্যা রয়েছে: স্টার অপারেটরের তুলনায় ডট অপারেটরের উচ্চতর অগ্রাধিকার রয়েছে, সুতরাং যদি আপনার কাছে পয়েন্টারযুক্ত স্ট্রাক্টের সাথে স্ট্রাক্টে পয়েন্টার যুক্ত স্ট্রাক্ট থাকে তবে ... এই দুটি সমতুল্য:

(*(*(*a).b).c).d

a->b->c->d

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


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

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

16
@effeffe, অপ বলছে যে ভাষা সহজে ব্যাখ্যা করা হতে পারে a.b.c.dযেমন (*(*(*a).b).c).d, রেন্ডারিং ->অপারেটর বেহুদা। সুতরাং ওপি'র সংস্করণ ( a.b.c.d) তুলনামূলকভাবে সমান পঠনযোগ্য a->b->c->d। এজন্য আপনার উত্তরটি ওপি-র প্রশ্নের উত্তর দেয় না।
শাহবাজ

4
@Shahbaz এটা একটা জাভা প্রোগ্রামার কেনার ক্ষেত্রে দেখা হতে পারে, সি / সি ++ প্রোগ্রামার বুঝতে হবে a.b.c.dএবং a->b->c->dদুই হিসাবে খুব ভিন্ন জিনিস: প্রথম একটি নেস্টেড উপ-বস্তু একটি একক মেমরির অ্যাক্সেস (মাত্র এই ক্ষেত্রে একটি একক মেমরির অবজেক্ট ), দ্বিতীয়টি হল তিনটি মেমরি অ্যাক্সেস, চারটি সম্ভাব্য স্বতন্ত্র বস্তুর মাধ্যমে পয়েন্টারগুলি তাড়া করে। এটি মেমরির বিন্যাসে একটি বিশাল পার্থক্য এবং আমি বিশ্বাস করি যে সি এই দুটি ক্ষেত্রে খুব দৃশ্যমানভাবে পৃথক করার ক্ষেত্রে সঠিক right
সিমেস্টার

2
@ শাহবাজ আমি এর অর্থ জাভা প্রোগ্রামারদের অপমান হিসাবে বোঝাতে চাইনি, এগুলি পুরোপুরি অন্তর্নিহিত পয়েন্টার সহ একটি ভাষায় অভ্যস্ত। যদি আমি জাভা প্রোগ্রামার হিসাবে উত্থিত হতাম, সম্ভবত আমিও একইভাবে চিন্তা করব ... যাইহোক, আমি আসলেই মনে করি যে অপারেটারের ওভারলোডিংটি আমরা সিতে দেখতে পাই অপটিমালার চেয়ে কম। যাইহোক, আমি স্বীকার করি যে আমরা সবাই গণিতবিদদের দ্বারা নষ্ট হয়ে গিয়েছি যারা বেশ কিছু কিছুর জন্য উদারপন্থী তাদের অপারেটরদের ওভারলোড করে। উপলব্ধ চিহ্নগুলির সেটটি সীমাবদ্ধ হওয়ায় আমি তাদের অনুপ্রেরণাটিও বুঝতে পারি। আমার ধারণা, শেষ পর্যন্ত আপনি কোথায় লাইনটি আঁকেন এটি কেবল প্রশ্ন ...
সায়স্টার - মনিকা পুনরুদ্ধার করুন

19

অস্পষ্ট কিছু না তৈরি করতে সিও একটি ভাল কাজ করে।

অবশ্যই উভয় জিনিস বোঝার জন্য বিন্দুটি ওভারলোড করা যেতে পারে, তবে তীরটি নিশ্চিত করে যে প্রোগ্রামার জানে যে সে পয়েন্টারে কাজ করছে ঠিক ঠিক ঠিক যখন কম্পাইলারটি আপনাকে দুটি অসম্পূর্ণ প্রকার মিশ্রিত করতে দিবে না।


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

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