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


126

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

#include <iostream>
using namespace std;

int main(){

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

উত্পাদন করে

2+3 = 15

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

2+3 = 5

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

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


96
আপনি ;প্রথম আউটপুট লাইনের শেষে সেমিকোলন চান , না <<। আপনি কী মুদ্রণ করছেন বলে আপনি মুদ্রণ করছেন না। আপনি করছেন cout << cout, যা মুদ্রণ করে 1(এটি ব্যবহার করে cout.operator bool(), আমি মনে করি)। তারপরে 5(থেকে 2+3) অবিলম্বে অনুসরণ করে, এটিকে পনের নম্বর বলে মনে হচ্ছে।
ইগোর ট্যান্ডেটনিক

5
@ স্টেফানলটেনার এটি সম্ভবত তখন জিসিসি 4 ব্যবহার করছে। জিসিসি 5 পর্যন্ত তাদের সম্পূর্ণরূপে মেনে চলার স্ট্রিম ছিল না, বিশেষত, এখনও পর্যন্ত তাদের রূপান্তর জড়িত ছিল।
বাযুমের Augen MIT

4
@ আইগোরট্যান্ডেটিক যা উত্তরের সূচনা বলে মনে হচ্ছে। এই প্রশ্নটির অনেকগুলি সূক্ষ্মতা রয়েছে যা প্রথম পঠনে প্রমাণিত হয় না।
মার্ক রান্সম

14
এই প্রশ্নটি বন্ধ করতে কেন লোকেরা ভোট দিয়ে চলেছে? এটি "দয়া করে আমাকে এই কোডটির মধ্যে কী ভুল তা বলুন না" তবে "কেন এই কোডটি এই আউটপুটটি উত্পাদন করে?" প্রথমটির উত্তরটি "আপনি একটি টাইপো করেছেন", হ্যাঁ, তবে দ্বিতীয়টির সংকলক কোডটি কীভাবে ব্যাখ্যা করছে, কেন এটি সংকলক ত্রুটি নয় এবং পয়েন্টার ঠিকানার পরিবর্তে এটি কীভাবে "1" পাচ্ছে তার একটি ব্যাখ্যা প্রয়োজন।
জাগডস্পায়ার

6
@ জ্যাজেডস্পায়ার যদি এটি কোনও টাইপোগ্রাফিক ত্রুটি না হয় তবে এটি খুব খারাপ প্রশ্ন কারণ এটি ইচ্ছাকৃতভাবে চিহ্নিত না করে ইচ্ছাকৃতভাবে এমন একটি অস্বাভাবিক রচনা ব্যবহার করে যা টাইপোগ্রাফিক ত্রুটির মতো দেখায়। যে কোনও উপায়ে, নিকটতম ভোটের দাবিদার। (যেহেতু কোনও টাইপোগ্রাফিক ত্রুটি বা খারাপ / বিদ্বেষের কারণে people এটি লোকেরা যাতে অন্যকে
ডেভিড শোয়ার্জ

উত্তর:


229

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

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, একটি নির্দিষ্ট ধরণের রূপান্তর অপারেটর সরবরাহ করে যা বুলিয়ান প্রসঙ্গে যেমন ব্যবহৃত হয় তেমন ব্যবহার করার উদ্দেশ্যে

while (cout) { PrintSomething(cout); }

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

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

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

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

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

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


1
@ টিটিসি আমি নিশ্চিত যে এই বিশেষ অঞ্চলে C ++ 03 এবং C ++ 98 এর মধ্যে কোনও পার্থক্য নেই। আমি মনে করি আমি সি ++ 03 এর সমস্ত উল্লেখ "প্রি-সি ++ 11" দিয়ে প্রতিস্থাপন করতে পারতাম, যদি এটি বিষয়গুলিকে স্পষ্ট করতে সহায়তা করে। আমি লিনাক্স এট আল-তে সংকলক এবং গ্রন্থাগারের সংস্করণটির জটিলতার সাথে মোটেই পরিচিত নই; আমি একজন উইন্ডোজ / এমএসভিসি লোক।
ইগোর ট্যান্ডেটনিক

4
আমি সি ++ 03 এবং সি ++ 98 এর মধ্যে নিটপিক করার চেষ্টা করছিলাম না; মুল বক্তব্যটি হ'ল লিবিসি ++ হ'ল সি ++ 11 এবং কেবলমাত্র নতুন; এটি সি ++ 98/03 এর সাথে সামঞ্জস্য করার চেষ্টা করে না।
টিসি

45

ইগোর যেমন বলেছেন, আপনি এটি সি ++ 11 লাইব্রেরি সহ পাবেন, যেখানে std::basic_iosএর operator boolপরিবর্তে রয়েছে operator void*তবে কোনওভাবে ঘোষিত হয়নি (বা হিসাবে বিবেচিত হবে না) explicit। সঠিক ঘোষণার জন্য এখানে দেখুন ।

উদাহরণস্বরূপ, একটি কনফার্মিং সি ++ 11 সংকলক একই ফলাফল দেবে

#include <iostream>
using namespace std;

int main() {
    cout << "2+3 = " << 
    static_cast<bool>(cout) << 2 + 3 << endl;
}

তবে আপনার ক্ষেত্রে, এটি static_cast<bool>(ভুলভাবে) অন্তর্নিহিত রূপান্তর হিসাবে অনুমোদিত।


সম্পাদনা: যেহেতু এটি স্বাভাবিক বা প্রত্যাশিত আচরণ নয়, তাই আপনার প্ল্যাটফর্ম, সংকলক সংস্করণ ইত্যাদি জানার জন্য এটি কার্যকর হতে পারে


সম্পাদনা 2: রেফারেন্সের জন্য, কোডটি সাধারণত হয় হিসাবে লেখা হয়

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

বা হিসাবে

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

এবং এটি দুটি শৈলীর সাথে একত্রিত হচ্ছে যা বাগটি প্রকাশ করেছে।


1
আপনার প্রথম প্রস্তাবিত সমাধান কোডটিতে একটি টাইপ রয়েছে। একজন খুব বেশি অপারেটর।
এরেরিকিকা

3
এখন আমি এটিও করছি, এটি অবশ্যই সংক্রামক হবে। ধন্যবাদ!
বেহুদা

1
হা! :) আমার উত্তরের প্রাথমিক সম্পাদনায় আমি সেমিকোলন যুক্ত করার পরামর্শ দিয়েছি, তবে লাইনের শেষে অপারেটরটি বুঝতে পারি নি। আমি ওপি এর সাথে একত্রে মনে করি, আমরা এটি টাইপগুলির সবচেয়ে উল্লেখযোগ্য ক্রম উত্পাদন করতে পেরেছি।
এরেরিকা

21

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

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

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

cout << cout;

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

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

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


11

পোস্ট করা কোডটি কোনও সি ++ 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 কোড যা অন্তর্নিহিত বুলিয়ান রূপান্তরগুলির উপর নির্ভর করে এই আন্তর্জাতিক স্ট্যান্ডার্ডটির সাথে সংকলন করতে ব্যর্থ হবে। নিম্নলিখিত রূপে এই ধরণের রূপান্তরগুলি ঘটে:

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

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

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


3
boolসি ++ 03 তে কোনও রূপান্তর বিদ্যমান নেই , তবে std::basic_ios::operator void*()শর্তাধীন বা লুপের নিয়ন্ত্রক প্রকাশ হিসাবে অর্থবহ তা রয়েছে ।
বেন ভয়েগট

7

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

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);

বাফার: empty

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

বিবৃতি: 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 = 15

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

বিবৃতি:

বাফার: 2+3 = 15\n

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


6
যদিও এটি সমস্ত সত্য (এবং সুন্দরভাবে ফর্ম্যাট করা) তবে আমি মনে করি এটি প্রশ্নটি করছে। আমি বিশ্বাস করি প্রশ্নের নিচে boils "কেন cout << coutউত্পাদন 1প্রথম স্থানে?" , এবং আপনি সবেমাত্র বলেছেন যে এটি সন্নিবেশ অপারেটর শৃঙ্খলা সম্পর্কিত আলোচনার মাঝামাঝি সময়ে ঘটে।
বেহুদা

1
যদিও সুন্দর ফর্ম্যাটিংয়ের জন্য +1। এটি আপনার প্রথম উত্তর হিসাবে বিবেচনা করে, আপনি যে সাহায্য করার চেষ্টা করছেন তা চমৎকার :) :)
গ্ল্ড্রাফেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.