سؤال

أعلم أن cout لديه مخزن مؤقت منذ عدة أيام، وعندما أبحث عنه في Google، يقال إن المخزن المؤقت يشبه المكدس ويحصل على إخراج cout وprintf من اليمين إلى اليسار، ثم أخرجهما (إلى وحدة التحكم أو الملف ) من الأعلى إلى الأسفل.مثله،

a = 1; b = 2; c = 3;
cout<<a<<b<<c<<endl;
buffer:|3|2|1|<-   (take “<-” as a poniter)

output:|3|2|<-     (output 1)
        |3|<-       (output 2)
        |<-         (output 3)

ثم أكتب الكود أدناه،

#include <iostream> 
using namespace std; 
int c = 6;
int f() 
{   
    c+=1; 
    return c; 
} 

int main() 
{ 
     int i = 0; 
     cout <<"i="<<i<<" i++="<<i++<<" i--="<<i--<<endl; 
     i = 0;
     printf("i=%d i++=%d i--=%d\n" , i , i++ ,i-- );

     cout<<f()<<" "<<f()<<" "<<f()<<endl; 
     c = 6;
     printf("%d %d %d\n" , f() , f() ,f() );
     system("pause");
     return 0; 
}

تحت VS2005، الإخراج هو

i=0 i++=-1 i--=0
i=0 i++=-1 i--=0
9 8 7
9 8 7

يبدو أن طريقة المكدس صحيحة ~ ومع ذلك ، قرأت C ++ Primer Plus بالأمس ، ويقال إن Cout يعمل من اليسار إلى اليمين ، في كل مرة يعيد فيها كائن (Cout) ، لذلك "هذه هي الميزة التي تتيح لك متسلسل الإخراج باستخدام الإدراج ".لكن الطريقة من اليسار إلى اليمين لا يمكن أن تفسر cout<

ثم النتاك أخبرني أن "عامل التشغيل << هو في الحقيقة عامل التشغيل ostream&<<(ostream& os, int)، لذا فإن هناك طريقة أخرى لكتابة ذلك وهي:عامل التشغيل<< ( عامل التشغيل<< ( عامل التشغيل<< ( cout, a ), b ), c ​​)"،

إذا تم تقييم الحجة الصحيحة أولاً، فمن الممكن شرحها.

الآن أنا في حيرة من أمري بشأن كيفية عمل المخزن المؤقت لـ cout، هل يمكن لأحد أن يساعدني؟

هل كانت مفيدة؟

المحلول

أنت تخلط الكثير من الأشياء.ان يذهب في موعد:

  • تفاصيل تنفيذ cout
  • مكالمات متسلسلة
  • اصطلاحات الدعوة

حاول أن تقرأ عنها بشكل منفصل.ولا تفكر في كل منهم دفعة واحدة.

printf("i=%d i++=%d i--=%d " , i , i++ ,i-- );

يستدعي السطر أعلاه سلوكًا غير محدد.اقرأ الأسئلة الشائعة 3.2.لاحظ أن ما لاحظته هو أحد الآثار الجانبية لاصطلاح استدعاء الوظيفة وطريقة تمرير المعلمات في المكدس من خلال تطبيق معين (أي.خاصة بك).لا يمكن ضمان أن يكون هذا هو نفسه إذا كنت تعمل على أجهزة أخرى.

أعتقد أنك تخلط بين ترتيب استدعاءات الوظائف والتخزين المؤقت.عندما يكون لديك cout عبارة متبوعة بإدراج متعددة << أنت في الواقع تستدعي استدعاءات دوال متعددة، واحدة تلو الأخرى.لذا، إذا كنت ستكتب:

cout << 42 << 0;

يعني حقا:أنت أتصل،

cout = operator<<(cout, 42)

ثم استخدم العودة في مكالمة أخرى لنفس المشغل على النحو التالي:

cout = operator<<(cout, 0)

ما اختبرته بما سبق لن يخبرك بأي شيء coutالتمثيل الداخلي.أقترح عليك إلقاء نظرة على ملفات الرأس لمعرفة المزيد.

نصائح أخرى

وكما تلميح العام، أبدا من أي وقت مضى استخدام ط ++ في نفس الخط استخدام آخر من أنا أو أنا -.

والمسألة هي أن الحجج وظيفة يمكن تقييمها في أي أمر، حتى إذا الحجج الدالة لها أي آثار جانبية (مثل عمليات زيادة وإنقاص) لا يمكنك أن تضمن أنها لن تعمل في الترتيب الذي تتوقع. هذا شيء لتجنب.

والشيء نفسه ينطبق على هذه الحالة، والذي يشبه إلى التوسع الفعلي لاستخدام cout الخاص بك:

وfunction1، و(function2 (فو)، بار)؛

ومترجم حر في evaulate شريط قبل استدعاء function2، أو العكس بالعكس. يمكنك نضمن أن function2 يعود قبل أن يتم استدعاء function1، وعلى سبيل المثال، ولكن ليس هذا حججهم يتم تقييمها في ترتيب معين.

وهذا يصبح مشكلة عندما تفعل شيئا مثل:

وfunction1، و(function2 (ط ++)، ط)؛

لديك أي وسيلة لتحديد ما إذا كانت "أنا" يتم تقييم قبل أو بعد "ط ++"، لذلك أنت من المحتمل أن تحصل على نتائج مختلفة مما كنت أتوقع، أو نتائج مختلفة مع المجمعين مختلفة أو إصدارات مختلفة حتى من نفس المجمع.

وخلاصة القول، تجنب التصريحات مع آثار جانبية. استخدام فقط منهم لو انهم البيان الوحيد على الخط أو إذا كنت تعرف أنك تعديل فقط في نفس المتغير مرة واحدة. (A "خط" يعني بيان واحد زائد منقوطة).

ما تراه هو سلوك غير معرف.

وتضاف i المحلية وc العالمية / تطرح عدة مرات بدون نقطة التسلسل. وهذا يعني أن القيم تحصل يمكن أن يكون أي شيء. يعتمد على مترجم، وربما أيضا بنية المعالج وعدد من النوى.

ويمكن اعتبار المخزن المؤقت cout كما الطابور، لذلك Alnitak هو الصحيح.

وبالإضافة إلى الإجابات الأخرى التي تشير بشكل صحيح إلى أن كنت ترى سلوك غير معرف، وأنا أحسب أنني أذكر أن std::cout يستخدم كائن من نوع std::streambuf للقيام التخزين المؤقت الداخلي. في الأساس هو فئة مجردة الذي يمثل العازلة (حجم هو خاص لتنفيذ ويمكن أن يكون حتى 0 لمخازن تيار unbufferd). واحد لstd::cout هو مكتوب هذا أنه عندما "تجاوزات" يتم مسح عليه في المعياري.

في الحقيقة، يمكنك تغيير std::streambuf المرتبطة std::cout (أو أي تيار لهذه المسألة). هذا مفيد في كثير من الأحيان إذا كنت تريد أن تفعل شيئا ذكي مثل جعل جميع std::cout يدعو غاية في ملف سجل أو شيء من هذا.

وكما قال dirkgently الذي يتم الخلط بين اصطلاح استدعاء مع تفاصيل أخرى، فهي لا علاقة لها تماما لSTD التخزين المؤقت :: cout ل.

وبالإضافة إلى ذلك، خلط نماذج الإخراج (printf وcout) محددة للتنفيذ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top