পয়েন্টারগুলির এই ব্যবহারটি কী অনাকাঙ্ক্ষিত?


108

আমি বর্তমানে পয়েন্টার শিখছি এবং আমার প্রফেসর একটি উদাহরণ হিসাবে কোডের এই অংশটি সরবরাহ করেছেন:

//We cannot predict the behavior of this program!

#include <iostream>
using namespace std;

int main()
{
    char * s = "My String";
    char s2[] = {'a', 'b', 'c', '\0'};

    cout << s2 << endl;

    return 0;
}

তিনি মন্তব্যে লিখেছিলেন যে আমরা প্রোগ্রামটির আচরণের পূর্বাভাস দিতে পারি না। যদিও এটি একে অপ্রত্যাশিত করে তোলে? আমি এটা দিয়ে ভুল কিছুই দেখতে।


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

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

2
@ দ্য পারম্যাগনেটিক ক্রোস্যান্ট: না। সূচনাটি আধুনিক সময়ে খারাপভাবে তৈরি।
অরবিটে 4-1015

2
@ দ্য প্যারাম্যাগনেটিক ক্রোস্যান্ট: যেমন আমি আগেই বলেছি, ভাষার ভাষায় "সংকলন করতে ব্যর্থ" হওয়ার জন্য খারাপ-গঠন কোডের প্রয়োজন হয় না। সংকলকগুলি কেবল একটি ডায়াগনস্টিক ইস্যু করার জন্য প্রয়োজনীয়। এর পরে তাদের কোড চালিয়ে যেতে এবং "সাফল্যের সাথে" অনুমতি দেওয়ার অনুমতি দেওয়া হয়। যাইহোক, এই জাতীয় কোডের আচরণটি ভাষা বর্ণ দ্বারা সংজ্ঞায়িত হয় না।
অ্যান্ট

2
আপনার প্রফেসর আপনাকে কী উত্তর দিয়েছিল তা আমি জানতে চাই।
ড্যানিয়েল ডব্লিউ। ক্রম্পটন

উত্তর:


125

প্রোগ্রামটির আচরণ অস্তিত্বহীন, কারণ এটি অ-গঠিত।

char* s = "My String";

এটি অবৈধ। 2011 এর আগে, এটি 12 বছর ধরে অবচিত করা হয়েছিল।

সঠিক লাইনটি হ'ল:

const char* s = "My String";

তা ছাড়া প্রোগ্রামটি ঠিক আছে। আপনার অধ্যাপক কম হুইস্কি পান করা উচিত!


10
বিস্ময়করভাবে এটি করে: main.cpp: 6: 16: সতর্কতা: আইএসও সি ++ স্ট্রিং ধ্রুবককে 'চর *' তে রূপান্তরিত করতে নিষেধ করেছে [-প্রেসেন্টিক]
মার্চিনজ

17
@ ব্ল্যাক: না, রূপান্তরটি অবৈধ যে ঘটনাটি প্রোগ্রামটিকে দূর্গঠিত করে তোলে। অতীতে এটি হ্রাস করা হয়েছিল । আমরা অতীতে আর নেই।
অরবিট

17
(যা নির্বোধ কারণ 12 বছর অবমূল্যায়নের উদ্দেশ্য ছিল)
অরবিটে

17
@ ব্ল্যাক: একটি প্রোগ্রাম যা খারাপভাবে তৈরি হয় তার আচরণটি "পুরোপুরি সংজ্ঞায়িত" হয় না
অরবিট

11
নির্বিশেষে, প্রশ্নটি সি ++ সম্পর্কিত, জিসিসির কোনও বিশেষ সংস্করণ সম্পর্কে নয়।
অরবিটে 4-1015

81

উত্তরটি হ'ল: এটি নির্ভর করে যে আপনি C ++ স্ট্যান্ডার্ডের সাথে কী সংগ্রহ করছেন। এই কোডটি বাদ দিয়ে সমস্ত কোডই সমস্ত মানকে পুরোপুরি সুসংহত করে:

char * s = "My String";

এখন, স্ট্রিং আক্ষরিকের টাইপ আছে const char[10]এবং আমরা এটির জন্য একটি নিরপেক্ষ পয়েন্টার আরম্ভ করার চেষ্টা করছি। charস্ট্রিং আক্ষরিকের পরিবার ব্যতীত অন্য সমস্ত ধরণের ক্ষেত্রে , এই জাতীয় সূচনাটি সর্বদা অবৈধ। উদাহরণ স্বরূপ:

const int arr[] = {1};
int *p = arr; // nope!

তবে, প্রি-সি ++ 11-এ স্ট্রিং লিটারেলের ক্ষেত্রে, exception4.2 / 2 এ ব্যতিক্রম ছিল:

একটি স্ট্রিং আক্ষরিক (২.১.4.৪) যা প্রশস্ত স্ট্রিং আক্ষরিক নয়, " পয়েন্টারে টু চর " টাইপের মূল্যে রূপান্তরিত হতে পারে ; [...]। উভয় ক্ষেত্রেই ফলাফলটি অ্যারের প্রথম উপাদানটির জন্য একটি পয়েন্টার। এই রূপান্তরটি কেবল তখনই বিবেচনা করা হয় যখন স্পষ্টভাবে উপযুক্ত পয়েন্টার টার্গেট ধরণের থাকে এবং যখন কোনও লভাল্যু থেকে কোনও মূল্যকে রূপান্তর করার কোনও সাধারণ প্রয়োজন হয় না। [দ্রষ্টব্য: এই রূপান্তরটি হ্রাস করা হয়েছে । আনেকেক্স ডি দেখুন ]

সুতরাং C ++ 03 এ কোডটি পুরোপুরি ঠিক আছে (যদিও অবমূল্যায়ন করা হয়েছে), এবং এর স্পষ্ট, অনুমানযোগ্য আচরণ রয়েছে।

সি ++ ১১-এ, সেই ব্লকটির অস্তিত্ব নেই - স্ট্রিং লিটারেলগুলিতে রূপান্তরিত হওয়ার জন্য এরকম কোনও ব্যতিক্রম নেই char*এবং তাই কোডটি ঠিক যেমনটি int*আমি প্রদান করেছি তার মতোই দুর্বোধ্য। সংকলকটি ডায়াগনস্টিক ইস্যু করার জন্য বাধ্যতামূলক, এবং আদর্শ ক্ষেত্রে যেমন সি ++ টাইপ সিস্টেমের স্পষ্ট লঙ্ঘন, আমরা আশা করি একটি ভাল সংকলক কেবলমাত্র এই ক্ষেত্রে মেনে চলবে না (যেমন একটি সতর্কতা জারি করে) তবে ব্যর্থ হবে সরাসরি।

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

const int arr[] = {1};
int *p = const_cast<int*>(arr); // OK, technically

এটির সাথে, প্রোগ্রামটির বাকী অংশগুলি পুরোপুরি ঠিক আছে, কারণ আপনি আর কখনও স্পর্শ করেন sনা। অ- পয়েন্টারটির মাধ্যমে একটি তৈরি- অবজেক্ট পড়া পুরোপুরি ঠিক। এই জাতীয় পয়েন্টারের মাধ্যমে একটি তৈরি- অবজেক্ট রচনা অপরিজ্ঞাত আচরণ:constconstconst

std::cout << *p; // fine, prints 1
*p = 5;          // will compile, but undefined behavior, which
                 // certainly qualifies as "unpredictable"

যেহেতু sআপনার কোডের কোথাও কোনও পরিবর্তন নেই , প্রোগ্রামটি সি ++ 03 তে ঠিক আছে, সি ++ 11-এ সংকলন করতে ব্যর্থ হওয়া উচিত তবে যাইহোক - এবং সংকলকরা এটির অনুমতি দেয়, এখনও এটির মধ্যে কোনও অপরিবর্তিত আচরণ নেই † । সংযোজকরা এখনও [ভুলভাবে] সি ++ 03 বিধিগুলির ব্যাখ্যা দিচ্ছেন এমন ভাতা দিয়ে, আমি এমন কোনও কিছুই দেখি না যা "অনাকাঙ্ক্ষিত" আচরণের দিকে পরিচালিত করে। sযদিও লিখুন , এবং সমস্ত বেট বন্ধ আছে। সি ++ 03 এবং সি ++ 11 উভয়ই।


† যদিও, আবার সংজ্ঞা অনুসারে অ-গঠিত কোডটি যুক্তিসঙ্গত আচরণের প্রত্যাশা দেয়
না not না বাদে ম্যাট ম্যাকনাব্বের উত্তর দেখুন


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

2
পছন্দ করুন এটি তাত্পর্যপূর্ণ আচরণ বা ত্রুটিযুক্ত কোডের বিভাগের নয় যা কোনও ডায়াগনস্টিক হিসাবে স্ট্যান্ডার্ড লেবেলগুলির প্রয়োজন নেই। এটি একটি সাধারণ ধরণের সিস্টেম লঙ্ঘন যা খুব অনুমানযোগ্য হতে হবে (সি ++ 03 তে সংকলন করে এবং সাধারণ কাজগুলি করে, সি ++ 11 তে সংকলন করতে ব্যর্থ হয়)। কোডটি অনুমানযোগ্য বলে প্রস্তাব দিতে আপনি সত্যই সংকলক বাগ (বা শৈল্পিক লাইসেন্স) ব্যবহার করতে পারবেন না - অন্যথায় সমস্ত কোড টোটোলজিক্যালি অনির্দেশ্য হতে পারে।
ব্যারি

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

1
না, তা হয় না। মানটি অসুস্থ-গঠিত প্রোগ্রামগুলির আচরণ সংজ্ঞায়িত করে না।
স্টিভ জেসোপ

1
@ সুপের্যাট: এটি ন্যায্য বিষয়, তবে আমি বিশ্বাস করি না এটির মূল কারণ। আমি মনে করি যে স্ট্যান্ডার্ডটি অসুস্থ-গঠিত প্রোগ্রামগুলির আচরণ নির্দিষ্ট করে না, এর মূল কারণটি হ'ল কম্পাইলাররা ভাষায় এক্সটেনশানগুলিকে সমর্থন করতে পারে যা ভালভাবে তৈরি হয় না (এমনটি অবজেক্টিভ সি যেমন করে) synt ব্যর্থ সংকলনের পরে পরিষ্কারের বাইরে মোট হারলিক্স তৈরির জন্য বাস্তবায়নের অনুমতি দেওয়া কেবল একটি বোনাস :-)
স্টিভ জেসপ

20

অন্যান্য উত্তরে কভার করা হয়েছে যে এ-তে const charঅ্যারে নির্ধারিত হওয়ার কারণে এই প্রোগ্রামটি C ++ 11-এ দুর্বৃত্ত char *

তবে প্রোগ্রামটি C ++ 11 এর আগেও দুর্গঠিত ছিল।

operator<<Overloads হয় <ostream>iostreamঅন্তর্ভুক্ত করার প্রয়োজনীয়তা ostreamসি ++ 11 এ যুক্ত করা হয়েছিল।

Icallyতিহাসিকভাবে , বেশিরভাগ বাস্তবায়নগুলি যাইহোক, সম্ভবত বাস্তবায়নের স্বাচ্ছন্দ্যে বা সম্ভবত আরও ভাল কিউআইআই সরবরাহ করার জন্য iostreamঅন্তর্ভুক্ত ছিল ostream

তবে এটি ওভারলোডগুলি নির্দিষ্ট না করে iostreamকেবল ostreamক্লাসটি সংজ্ঞায়িত করার জন্য উপযুক্ত হবে foroperator<<


13

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

অন্যথায়, এই প্রোগ্রামটি আমার কাছে ভালভাবে সংজ্ঞায়িত প্রদর্শিত হয়েছে:

  • প্যারামিটারগুলি (যেমন এর সাথে cout << s2) পাস করার পরে অক্ষর অ্যারে কীভাবে অক্ষর নির্দেশক হয়ে যায় তা নির্দেশ করে এমন নিয়মগুলি সুসংজ্ঞায়িত হয়।
  • অ্যারেটি নাল-টার্মিনেটেড, যা (বা ক ) operator<<দিয়ে শর্তযুক্ত ।char*const char*
  • #include <iostream>অন্তর্ভুক্ত রয়েছে <ostream>, যা ঘুরেফিরে সংজ্ঞা দেয় operator<<(ostream&, const char*), তাই সবকিছু ঠিকঠাকভাবে প্রদর্শিত হবে।

12

উপরে বর্ণিত কারণে আপনি সংকলকটির আচরণ সম্পর্কে ভবিষ্যদ্বাণী করতে পারবেন না। (এটি সংকলন করতে ব্যর্থ হওয়া উচিত , কিন্তু নাও পারে))

সংকলন সফল হয়, তাহলে আচরণটি ভাল সংজ্ঞাযুক্ত। আপনি অবশ্যই প্রোগ্রামটির আচরণের পূর্বাভাস দিতে পারেন।

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

সুতরাং আমি আপনার অধ্যাপকের বক্তব্য ভুল বলতে চাই। এই কোডটির সাথে सामना করার সময় আপনি সংকলকটির আচরণের পূর্বাভাস দিতে পারবেন না তবে এটি প্রোগ্রামের আচরণ থেকে পৃথক । সুতরাং যদি তিনি নিটগুলি তুলতে চলেছেন তবে তিনি নিশ্চিত হন যে তিনি ঠিক আছেন। অথবা, অবশ্যই, আপনি তাকে ভুল জিজ্ঞাসা করতে পারেন এবং ভুলটি তিনি যা বলেছিলেন তার অনুবাদে।


10

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

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

আমার ব্যক্তিগত পছন্দটি হ'ল ডিস্ক-ভিত্তিক সিস্টেমগুলিকে আউটপুট ফাইলটির নতুন নামকরণ করা, বিরল ঘটনাগুলির জন্য অনুমতি দেওয়া যখন সেই বিভ্রান্তি এড়ানো যায় যখন ভুলভাবে বিশ্বাস করা হয় যে কোনও একটি নতুন কোড চালাচ্ছে এবং এম্বেডড-প্রোগ্রামিংয়ের জন্য সিস্টেমগুলি প্রতিটি প্রকল্পের জন্য একটি প্রোগ্রামারকে নির্দিষ্ট করার অনুমতি দেয় এমন একটি প্রোগ্রাম যা লোড করা উচিত যদি কোনও নাম অনুসারে কার্যকর হয় না [আদর্শভাবে এমন কিছু যা নিরাপদে কোনও ব্যবহারযোগ্য প্রোগ্রামের অভাবকে ইঙ্গিত করে]। এম্বেডড-সিস্টেম সরঞ্জাম-সেটটিতে সাধারণত এই জাতীয় প্রোগ্রামটি কী করা উচিত তা জানার উপায় ছিল না, তবে বেশিরভাগ ক্ষেত্রেই কোনও সিস্টেমের জন্য "রিয়েল" কোড লেখার কারও কাছে কিছু হার্ডওয়্যার-টেস্ট কোড অ্যাক্সেস থাকে যা সহজেই মানিয়ে নিতে পারে উদ্দেশ্য। আমি জানি না যে আমি নামকরণের আচরণটি দেখেছি, তবে,

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.