the - c++ প্রোগ্রামিং বই



কোট কোডের এই স্নিপেটে কেন "2+3=15" মুদ্রণ করে? (4)

অপ্রত্যাশিত ফলাফলের কারণ টাইপো। আপনি সম্ভবত বোঝাতে চেয়েছিলেন

cout << "2+3 = "
     << 2 + 3 << endl;

যদি আমরা প্রত্যাশিত আউটপুটযুক্ত স্ট্রিংগুলিকে অগ্রাহ্য করি তবে আমাদের সাথে রেখে দেওয়া হবে:

cout << cout;

যেহেতু সি ++ 11, এটি অ-গঠনমূলক। std::cout এমন কোনও কিছুর ক্ষেত্রে std::basic_ostream<char>::operator<< রূপান্তরিত নয় যে std::basic_ostream<char>::operator<< (বা কোনও সদস্যের ওভারলোড নয়) তা গ্রহণ করবে। অতএব সংকলক অনুসারে একটি মানক কমপক্ষে আপনাকে এটি করার জন্য সতর্ক করতে হবে। আমার সংকলক আপনার প্রোগ্রামটি সংকলন করতে অস্বীকার করেছিল।

std::cout রূপান্তরিত হবে এবং স্ট্রিম ইনপুট অপারেটরের বোল ওভারলোডটি ১ টি পর্যবেক্ষণ করা আউটপুট পাবে However তবে, ওভারলোডটি সুস্পষ্ট, সুতরাং এটি কোনও নিখুঁত রূপান্তরকে অনুমতি দেবে না। এটি প্রদর্শিত হয় যে আপনার সংকলক / স্ট্যান্ডার্ড গ্রন্থাগার বাস্তবায়ন কঠোরভাবে মানের সাথে খাপ খায় না।

প্রাক-সি ++ 11 স্ট্যান্ডার্ডে এটি ভালভাবে গঠিত। তারপরে std::cout এর std::cout void* একটি অন্তর্নিহিত রূপান্তর অপারেটর ছিল যার স্ট্রিম ইনপুট অপারেটর ওভারলোড has এর জন্য আউটপুট তবে ভিন্ন হবে। এটি std::cout অবজেক্টের মেমরি ঠিকানা মুদ্রণ করবে।

নীচের প্রোগ্রামটির আউটপুট কেন এটি হয়?

#include <iostream>
using namespace std;

int main(){

    cout << "2+3 = " <<
    cout << 2 + 3 << endl;
}

উত্পাদন করে

2+3 = 15

পরিবর্তে প্রত্যাশিত

2+3 = 5

এই প্রশ্নটি ইতিমধ্যে একাধিক ঘনিষ্ঠ / চক্র পুনরায় খোলা গেছে।

ভোট দেওয়ার আগে, দয়া করে এই সমস্যাটি সম্পর্কে এই মেটা আলোচনাটি বিবেচনা করুন।


Answer #1

আপনি সহজেই এইভাবে আপনার কোডটি ডিবাগ করতে পারেন। আপনি যখন cout ব্যবহার করেন তখন আপনার আউটপুটটি বাফার হয় যাতে আপনি এটির বিশ্লেষণ করতে পারেন:

কল্টের প্রথম ঘটনাটি বাফার এবং অপারেটরের প্রতিনিধিত্ব করে << বাফারটির শেষে যুক্ত হওয়ার উপস্থাপন করে। অপারেটরের ফলাফল << আপনার cout আউটপুট স্ট্রিম। আপনি থেকে শুরু:

cout << "2+3 = " << cout << 2 + 3 << endl;

উপরের বর্ণিত বিধি প্রয়োগ করার পরে আপনি এর মতো ক্রিয়াগুলির একটি সেট পাবেন:

buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);

যেমন আমি আগে বলেছি বাফার ফলাফলের আগেই buffer.append() বাফার হয়। ভিক্ষা শুরুতে আপনার বাফারটি খালি এবং প্রক্রিয়া করার জন্য আপনার কাছে নিম্নলিখিত বিবৃতি রয়েছে:

বিবৃতি: buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);

বাফার: খালি

প্রথমে আপনার কাছে buffer.append("2+3 = ") যা প্রদত্ত স্ট্রিংটি সরাসরি বাফারে রাখে এবং বাফার হয়ে যায়। এখন আপনার রাজ্যটি দেখতে এমন দেখাচ্ছে:

বিবৃতি: buffer.append(cout).append(2 + 3).append(endl);

বাফার: 2 + 3   =  

এর পরে আপনি আপনার বিবৃতিটি বিশ্লেষণ চালিয়ে যান এবং বাফারের শেষে যুক্ত হওয়ার যুক্তি হিসাবে আপনি cout পেরিয়ে আসেন। cout 1 হিসাবে বিবেচনা করা হয় তাই আপনি আপনার বাফার শেষে 1 যুক্ত করবেন। এখন আপনি এই অবস্থায় আছেন:

বিবৃতি: buffer.append(2 + 3).append(endl);

বাফার: 2 + 3   =   1

আপনার বাফারে থাকা পরবর্তী জিনিসটি 2 + 3 এবং যেহেতু আউটপুট অপারেটরের তুলনায় সংযোজনের অগ্রাধিকার রয়েছে আপনি প্রথমে এই দুটি সংখ্যা যুক্ত করবেন এবং তারপরে আপনি ফলাফলটি বাফারে রাখবেন। এর পরে আপনি পাবেন:

বিবৃতি: buffer.append(endl);

বাফার: 2 + 3   =   1 5

অবশেষে আপনি বাফারের শেষে endl মান যুক্ত করুন এবং আপনার কাছে রয়েছে:

বিবৃতি:

বাফার: 2 + 3   =   1 5 \ n

এই প্রক্রিয়াটির পরে বাফার থেকে অক্ষরগুলি বাফার থেকে একের পর এক স্ট্যান্ডার্ড আউটপুটে মুদ্রিত হয়। সুতরাং আপনার কোডের ফলাফলটি 2+3 = 15 । আপনি যদি এটি তাকান তবে আপনি মুদ্রণের চেষ্টা করেছিলেন cout থেকে অতিরিক্ত 1 পান। আপনার বিবৃতি থেকে << cout সরিয়ে আপনি পছন্দসই আউটপুট পাবেন।


Answer #2

ইচ্ছাকৃতভাবে বা দুর্ঘটনাক্রমে, আপনার << প্রথম আউটপুট লাইনের শেষে, যেখানে আপনি সম্ভবত বোঝাতে চেয়েছিলেন ; । সুতরাং আপনি মূলত আছে

cout << "2+3 = ";  // this, of course, prints "2+3 = "
cout << cout;      // this prints "1"
cout << 2 + 3;     // this prints "5"
cout << endl;      // this finishes the line

সুতরাং প্রশ্নটি এখানে ফুটে উঠেছে: কেন cout << cout; "1" মুদ্রণ করবেন?

এটি সম্ভবত আশ্চর্যজনকভাবে, সূক্ষ্ম হিসাবে প্রমাণিত হয়। std::cout std::basic_ios , তার বেস ক্লাসের মাধ্যমে std::basic_ios , একটি নির্দিষ্ট ধরণের রূপান্তর অপারেটর সরবরাহ করে যা বুলিয়ান প্রসঙ্গে ব্যবহৃত হতে পারে

while (cout) { PrintSomething(cout); }

এটি একটি অত্যন্ত দরিদ্র উদাহরণ, কারণ আউটপুট ব্যর্থ হওয়া কঠিন - তবে std::basic_ios আসলে ইনপুট এবং আউটপুট উভয় প্রবাহের জন্য একটি বেস শ্রেণি, এবং std::basic_ios জন্য এটি আরও বেশি std::basic_ios করে:

int value;
while (cin >> value) { DoSomethingWith(value); }

(স্ট্রিমের শেষে লুপ থেকে বেরিয়ে যায়, বা যখন স্ট্রিম অক্ষরগুলি বৈধ পূর্ণসংখ্যার গঠন করে না)।

এখন, রূপান্তরকারী অপারেটরের সঠিক সংজ্ঞাটি স্ট্যান্ডার্ডের C ++ 03 এবং C ++ 11 সংস্করণের মধ্যে পরিবর্তিত হয়েছে। পুরানো সংস্করণগুলিতে এটি operator void*() const; (সাধারণত return fail() ? NULL : this; হিসাবে প্রয়োগ করা return fail() ? NULL : this; ), নতুন ক্ষেত্রে এটি explicit operator bool() const; (সাধারণত return !fail(); হিসাবে কার্যকর return !fail(); )। উভয় ঘোষণাগুলি বুলিয়ান প্রসঙ্গে ভাল কাজ করে, তবে যখন এ জাতীয় প্রসঙ্গে বাইরে (ভুল) ব্যবহার করা হয় তখন আলাদা আচরণ করে।

বিশেষত, সি ++ 03 বিধি অনুসারে, cout << cout.operator void*() কে cout << cout.operator void*() হিসাবে ব্যাখ্যা করা হবে এবং কিছু ঠিকানা মুদ্রণ করা হবে। সি ++ ১১ বিধি cout << cout , cout << cout মোটেও সংকলন করা উচিত নয়, কারণ অপারেটরটি explicit ঘোষিত হয় এবং সুতরাং প্রকৃত রূপান্তরগুলিতে অংশ নিতে পারে না। এটি আসলে পরিবর্তনের প্রাথমিক প্রেরণা ছিল - সংবেদনহীন কোডটি সংকলন থেকে রোধ করা। একটি সংকলক যা উভয় স্ট্যান্ডার্ডকে মেনে চলে এমন কোনও প্রোগ্রাম তৈরি করে না যা "1" মুদ্রণ করে।

স্পষ্টতই, কিছু সি ++ প্রয়োগগুলি সংযোজক এবং লাইব্রেরিটিকে এমনভাবে মিশ্রিত করতে এবং মেলানোর অনুমতি দেয় যা অ-অনুসরনকারী ফলাফলটি উত্পন্ন করে (@ স্টিফটালেকনারের উদ্ধৃতি দিয়ে: "আমি এক্সকোডে একটি সেটিংস পেয়েছি যা 1 উত্পাদন করে এবং অন্য একটি সেটিংস যা একটি ঠিকানা দেয়: ভাষা উপভাষা সি ++ 98 "স্ট্যান্ডার্ড লাইব্রেরি লাইবসি ++ (সি ++ 11 সাপোর্টের সাথে এলএলভিএম স্ট্যান্ডার্ড লাইব্রেরি) এর সাথে মিলিত হয়েছে" 1 টি পাওয়া যায়, যেখানে সি ++ 98 লিবিস্টডিসি (জিএনও সি ++ স্ট্যান্ডার্ড লাইব্রেরি) এর সাথে মিলিত একটি ঠিকানা দেয়; ")। আপনার কাছে সি ++ 03-স্টাইলের সংকলক থাকতে পারে যা explicit রূপান্তর অপারেটরগুলি বুঝতে পারে না (যা সি ++ 11 তে নতুন) একটি সি ++ 11-স্টাইল লাইব্রেরির সাথে মিলিত যা রূপান্তরকে operator bool() হিসাবে সংজ্ঞায়িত করে। এই জাতীয় মিশ্রণের সাহায্যে, cout << cout.operator bool() কে cout << cout.operator bool() হিসাবে ব্যাখ্যা করা সম্ভব হয়, যা cout << cout.operator bool() কেবল cout << true এবং "1" মুদ্রণ করে।


Answer #3

পোস্ট করা কোডটি কোনও সি ++ 11 (বা পরবর্তী সংস্করণকারী সংকলক) এর জন্য সংকলন করা উচিত নয়, তবে এটি প্রাক সি ++ 11 বাস্তবায়ন সম্পর্কে কোনও সতর্কতা ছাড়াই সংকলন করা উচিত।

পার্থক্যটি হ'ল সি ++ 11 একটি স্রোতকে একটি স্পষ্টভাবে বুলে রূপান্তরিত করেছে:

C.2.15 ধারা 27: ইনপুট / আউটপুট লাইব্রেরি [diff.cpp03.input.output] 27.7.2.1.3, 27.7.3.4, 27.5.5.4

পরিবর্তন: বিদ্যমান বুলিয়ান রূপান্তর অপারেটরগুলিতে সুস্পষ্টর ব্যবহার নির্দিষ্ট করুন
যুক্তি: উদ্দেশ্য পরিষ্কার করুন, কর্মক্ষেত্র এড়ানো।
মূল বৈশিষ্ট্যের উপর প্রভাব: কার্যকর সি ++ 2003 কোড যা অন্তর্নিহিত বুলিয়ান রূপান্তরগুলির উপর নির্ভর করে এই আন্তর্জাতিক স্ট্যান্ডার্ডটির সাথে সংকলন করতে ব্যর্থ হবে। নিম্নলিখিত রূপে এই ধরণের রূপান্তরগুলি ঘটে:

  • কোনও ফাংশনে একটি মান পাস করা যা বিল টাইপের আর্গুমেন্ট গ্রহণ করে;
    ...

অস্ট্রিম অপারেটর << একটি বুল প্যারামিটার দিয়ে সংজ্ঞায়িত করা হয়। যেহেতু বুলের রূপান্তর বিদ্যমান ছিল (এবং এটি স্পষ্ট ছিল না) প্রাক-সি ++ ১১, cout << cout এ অনুবাদ হয়েছিল cout << true যা ফলন করে 1।

এবং C.2.15 অনুসারে, এটি আর C ++ 11 দিয়ে আরম্ভ করে সংকলন করা উচিত নয়।





c++