উত্তর:
আমি অবাক হয়েছি যে এই প্রশ্নের প্রত্যেকেই দাবি করেছে যে এটির std::cout
চেয়ে ভাল printf
, এমনকি যদি প্রশ্নটি কেবল ভিন্নতা চেয়েছিল। এখন, একটি পার্থক্য আছে - std::cout
হয় C ++, ও printf
সি (তবে, আপনি এটি C ++ ব্যবহার করতে পারেন, শুধু ভালো হয় প্রায় C থেকে অন্য কিছু)। এখন, আমি এখানে সৎ হব; উভয় printf
এবং std::cout
তাদের সুবিধা আছে।
std::cout
এক্সটেনসিবল আমি জানি যে লোকেরা printf
এটিও এক্সটেনসিবল বলবে , তবে এই জাতীয় বর্ধনের কথা সি স্ট্যান্ডার্ডে উল্লেখ করা হয়নি (সুতরাং আপনাকে অ-মানক বৈশিষ্ট্যগুলি ব্যবহার করতে হবে - তবে সাধারণ অ-মানক বৈশিষ্ট্যটিও উপস্থিত নেই), এবং এই জাতীয় এক্সটেনশানগুলি একটি অক্ষর (সুতরাং ইতিমধ্যে বিদ্যমান ফর্ম্যাটটির সাথে দ্বন্দ্ব করা সহজ)।
বিপরীতে printf
, std::cout
অপারেটর ওভারলোডিংয়ের উপর সম্পূর্ণ নির্ভর করে, তাই কাস্টম ফর্ম্যাটগুলির সাথে কোনও সমস্যা নেই - আপনারা যা করেন তা হ'ল std::ostream
প্রথম আর্গুমেন্ট এবং দ্বিতীয় ধরণের হিসাবে আপনার টাইপ হিসাবে গ্রহণ করা একটি সাব্রোটিনকে সংজ্ঞায়িত করা । যেমন, কোনও নেমস্পেসের সমস্যা নেই - যতক্ষণ না আপনার ক্লাস থাকে (যা একটি চরিত্রের মধ্যে সীমাবদ্ধ নয়), আপনি std::ostream
এটির জন্য ওভারলোডিং কাজ করতে পারেন ।
যাইহোক, আমি সন্দেহ করি যে অনেক লোক প্রসারিত করতে চাইবে ostream
(সত্য কথা বলতে, আমি খুব কমই এ জাতীয় এক্সটেনশানগুলি দেখেছি, যদিও তারা সহজ করা সহজ)। তবে আপনার প্রয়োজন হলে এটি এখানে।
এটিকে সহজে লক্ষ্য করা যায়নি, উভয় printf
এবং std::cout
বিভিন্ন সিনট্যাক্স ব্যবহার করুন। printf
প্যাটার্ন স্ট্রিং এবং পরিবর্তনশীল-দৈর্ঘ্যের আর্গুমেন্ট তালিকাগুলি ব্যবহার করে স্ট্যান্ডার্ড ফাংশন সিনট্যাক্স ব্যবহার করে। প্রকৃতপক্ষে, printf
সি এগুলির একটি কারণ - printf
ফর্ম্যাটগুলি এগুলি ব্যতীত ব্যবহারের জন্য খুব জটিল। তবে, std::cout
একটি পৃথক এপিআই ব্যবহার করে - যে operator <<
এপিআই নিজেই ফিরে আসে।
সাধারণত, এর অর্থ হ'ল সি সংস্করণটি ছোট হবে তবে বেশিরভাগ ক্ষেত্রে এটি কোনও ব্যাপার নয়। আপনি অনেক যুক্তি মুদ্রণ করার সময় পার্থক্যটি লক্ষণীয়। আপনার যদি Error 2: File not found.
ত্রুটি নম্বরটি ধরে ধরে এর মতো কিছু লিখতে হয় এবং এর বিবরণ স্থানধারক হয় তবে কোডটি এর মতো দেখাবে। উভয় উদাহরণ অভিন্নভাবে কাজ করে (ভাল, সাজানোর, std::endl
আসলে বাফার ফ্লাশ করে)।
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
এটি খুব পাগল হিসাবে প্রদর্শিত হবে না (এটি মাত্র দু'গুণ বেশি), যখন আপনি আসলে যুক্তিগুলি ছাপানোর পরিবর্তে আর্গুমেন্টগুলি ফর্ম্যাট করেন তখন জিনিসগুলি আরও বেশি পাগল হয়। উদাহরণস্বরূপ, এর মতো 0x0424
কোনও কিছু প্রিন্ট করা কেবল উন্মাদ। এটি std::cout
রাষ্ট্র এবং আসল মানগুলির মিশ্রণের কারণে ঘটে । আমি এমন কোন ভাষা দেখিনি যেখানে এর মতো কিছু std::setfill
হ'ল টাইপ হবে (অবশ্যই সি ++ ব্যতীত)। printf
যুক্তি এবং প্রকৃত প্রকারটি স্পষ্টভাবে পৃথক করে। আমি এর printf
সংস্করণটির তুলনায় সত্যই এটির সংস্করণটি বজায় রাখতে পছন্দ করি (যদিও এটি ক্রিপ্টিক ধরনের মনে হয়) iostream
(এটিতে খুব বেশি শব্দ রয়েছে)।
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
এখানেই printf
মিথ্যার আসল সুবিধা । printf
ফরম্যাট স্ট্রিং ভাল একটি স্ট্রিং ...। এটির operator <<
অপব্যবহারের তুলনায় অনুবাদ করা সত্যই সহজ করে তোলে iostream
। ধরে নিই যে gettext()
ফাংশনটি অনুবাদ করে এবং আপনি দেখাতে চান Error 2: File not found.
, পূর্ববর্তী দেখানো ফর্ম্যাট স্ট্রিংয়ের অনুবাদ পেতে কোডটি দেখতে এরকম হবে:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
এখন, ধরে নেওয়া যাক আমরা ফিকশনিশে অনুবাদ করি, যেখানে বর্ণনার পরে ত্রুটি সংখ্যাটি রয়েছে। অনুবাদকৃত স্ট্রিংয়ের মতো দেখতে হবে %2$s oru %1$d.\n
। এখন, এটি সি ++ এ কীভাবে করবেন? ঠিক আছে, আমার কোনও ধারণা নেই। আমি অনুমান করি আপনি জাল তৈরি করতে পারেন iostream
যা অনুবাদ বা আপনি কিছু অনুবাদ printf
করতে পারেন gettext
purposes অবশ্যই, $
সি স্ট্যান্ডার্ড নয়, তবে এটি এত সাধারণ যে এটি আমার মতে ব্যবহার করা নিরাপদ।
সি এর অনেকগুলি পূর্ণসংখ্যার প্রকার রয়েছে, এবং সি ++ রয়েছে। std::cout
হ্যান্ডলগুলি আপনার জন্য সব ধরনের, যখন printf
একটি পূর্ণসংখ্যা ধরনের উপর নির্ভর করে নির্দিষ্ট সিনট্যাক্স প্রয়োজন (সেখানে অ পূর্ণসংখ্যা ধরনের হয়, কিন্তু শুধুমাত্র অ পূর্ণসংখ্যা টাইপ আপনার সাথে বাস্তবে ব্যবহার করবে printf
হয় const char *
(গ স্ট্রিং, ব্যবহার প্রাপ্ত করা যাবে to_c
পদ্ধতি std::string
))। উদাহরণস্বরূপ, মুদ্রণের জন্য size_t
, আপনাকে ব্যবহার করতে হবে %zd
, যখন ব্যবহারের প্রয়োজন int64_t
হবে %"PRId64"
। টেবিলগুলি http://en.cppreferences.com/w/cpp/io/c/fprintf এবং http://en.cppreferences.com/w/cpp/tyype/integer এ উপলব্ধ ।
\0
যেহেতু printf
সি স্ট্রিংগুলি সি ++ স্ট্রিংয়ের বিপরীতে ব্যবহার করে, এটি নির্দিষ্ট কৌশল ছাড়া NUL বাইট মুদ্রণ করতে পারে না। নির্দিষ্ট ক্ষেত্রে এটি ব্যবহার করা সম্ভব %c
সঙ্গে '\0'
, একটি আর্গুমেন্ট হিসাবে যদিও যে স্পষ্টতই হ্যাক করে।
আপডেট করুন: এটা পরিনত হয় যে iostream
, তাই ধীর এটি সাধারণত ধীর আপনার হার্ড ড্রাইভে চেয়ে এর (আপনি ফাইলে আপনার প্রোগ্রাম পুনর্নির্দেশ থাকেন)। stdio
আপনার যদি প্রচুর ডেটা আউটপুট প্রয়োজন হয় তবে এর সাথে সিঙ্ক্রোনাইজেশন অক্ষম করা সহায়তা করতে পারে। যদি পারফরম্যান্সটি সত্যিকারের উদ্বেগ হয় তবে (STDOUT- এ কয়েকটি লাইন লেখার বিপরীতে), কেবল ব্যবহার করুন printf
।
প্রত্যেকেই মনে করে যে তারা পারফরম্যান্সের বিষয়ে যত্নশীল, তবে কেউ এটি পরিমাপ করতে বিরক্ত করে না। আমার উত্তর হ'ল I / O যাই হোক বাধা হ'ল, আপনি ব্যবহার করেন printf
বা না কেন, তা গুরুত্বপূর্ণ নয় iostream
। আমি মনে করি এটি সমাবেশে তাত্ক্ষণিকভাবে দেখার চেয়ে দ্রুততর printf
হতে পারে ( -O3
সংকলক বিকল্পটি ব্যবহার করে ঝাঁকুনির সাহায্যে সংকলিত )। আমার ত্রুটির উদাহরণ হিসাবে ধরে নেওয়া, printf
উদাহরণ উদাহরণের চেয়ে কম কল করে cout
। এটি int main
সঙ্গে printf
:
main: @ @main
@ BB#0:
push {lr}
ldr r0, .LCPI0_0
ldr r2, .LCPI0_1
mov r1, #2
bl printf
mov r0, #0
pop {lr}
mov pc, lr
.align 2
@ BB#1:
আপনি সহজেই লক্ষ্য করতে পারেন যে দুটি স্ট্রিং এবং 2
(সংখ্যা) printf
আর্গুমেন্ট হিসাবে চাপানো হয়েছে। এটা সম্বন্ধে; আর কিছুই নেই। তুলনার জন্য, এটি iostream
সমাবেশে সংকলিত হয়। না, কোন ইনলাইনিং নেই; প্রতিটি একক operator <<
কল মানেই অন্য একটি যুক্তি যুক্ত সেট call
main: @ @main
@ BB#0:
push {r4, r5, lr}
ldr r4, .LCPI0_0
ldr r1, .LCPI0_1
mov r2, #6
mov r3, #0
mov r0, r4
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov r0, r4
mov r1, #2
bl _ZNSolsEi
ldr r1, .LCPI0_2
mov r2, #2
mov r3, #0
mov r4, r0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_3
mov r0, r4
mov r2, #14
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_4
mov r0, r4
mov r2, #1
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r0, [r4]
sub r0, r0, #24
ldr r0, [r0]
add r0, r0, r4
ldr r5, [r0, #240]
cmp r5, #0
beq .LBB0_5
@ BB#1: @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
ldrb r0, [r5, #28]
cmp r0, #0
beq .LBB0_3
@ BB#2:
ldrb r0, [r5, #39]
b .LBB0_4
.LBB0_3:
mov r0, r5
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr r0, [r5]
mov r1, #10
ldr r2, [r0, #24]
mov r0, r5
mov lr, pc
mov pc, r2
.LBB0_4: @ %_ZNKSt5ctypeIcE5widenEc.exit
lsl r0, r0, #24
asr r1, r0, #24
mov r0, r4
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov r0, #0
pop {r4, r5, lr}
mov pc, lr
.LBB0_5:
bl _ZSt16__throw_bad_castv
.align 2
@ BB#6:
যাইহোক, সত্যি কথা বলতে, এর অর্থ কিছুই নেই, কারণ I / O যাই হোক বাধা। আমি কেবল এটি দেখাতে চেয়েছিলাম যে iostream
এটি দ্রুত নয় কারণ এটি "প্রকারের নিরাপদ"। বেশিরভাগ সি বাস্তবায়নগুলি printf
গণিত গোটো ব্যবহার করে ফর্ম্যাটগুলি বাস্তবায়িত করে, তাই printf
কম্পাইলার সম্পর্কে অবহিত printf
না হওয়া সত্ত্বেও এটি দ্রুততর হতে পারে (কোনও সংকলক printf
নির্দিষ্ট ক্ষেত্রে অপ্টিমাইজ করতে পারে - ধ্রুব স্ট্রিংয়ের সমাপ্তি \n
সাধারণত অনুকূলিত হয় puts
) ।
আপনি কেন উত্তরাধিকারী হতে চান ostream
তা আমি জানি না, তবে আমি যত্ন করি না। এটাও সম্ভব FILE
।
class MyFile : public FILE {}
সত্য, পরিবর্তনশীল দৈর্ঘ্যের আর্গুমেন্ট তালিকার কোনও সুরক্ষা নেই, তবে এটি গুরুত্বপূর্ণ নয়, কারণ জনপ্রিয় সি সংকলকগণ printf
যদি আপনি সতর্কতা সক্ষম করেন তবে ফর্ম্যাট স্ট্রিংয়ের সাথে সমস্যাগুলি সনাক্ত করতে পারে । আসলে, ক্ল্যাং সতর্কতা সক্ষম না করে এটি করতে পারে।
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
std::sort
, যা কোনওভাবে আশ্চর্যজনকভাবে qsort
(2 বার) এর তুলনায় দ্রুততর হয় ) নির্বাহযোগ্য আকারের ব্যয়)।
থেকে সি ++ প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী :
[15.1] আমি কেন
<iostream>
গতানুগতিক পরিবর্তে ব্যবহার করব<cstdio>
?প্রকারের সুরক্ষা বাড়ান, ত্রুটিগুলি হ্রাস করুন, এক্সটেনসিবিলিটিটিকে মঞ্জুরি দিন এবং উত্তরাধিকার প্রদান করুন।
printf()
তর্কযোগ্যভাবে ভাঙা নয়, এবংscanf()
ত্রুটিযুক্ত প্রবণ হওয়া সত্ত্বেও সম্ভবত জীবিত, তবে উভয়ই সি ++ আই / ও কি করতে পারে সে সম্পর্কে সীমাবদ্ধ। সি ++ আই / ও (ব্যবহার<<
এবং>>
) সি এর সাথে সম্পর্কিত (ব্যবহারprintf()
এবংscanf()
):
- আরও প্রকারের সুরক্ষিত:
<iostream>
আই / ও'ড হ'ল ধরণের সংস্থার দ্বারা স্থিরভাবে জানা যায় known বিপরীতে,<cstdio>
গতিশীলভাবে প্রকারগুলি বের করতে "%" ক্ষেত্রগুলি ব্যবহার করুন।- ত্রুটিযুক্ত প্রবণতা: এর সাথে
<iostream>
, রিডানডেন্ট "%" টোকেন নেই যা আসল বস্তুগুলি I / O'd এর সাথে সামঞ্জস্য রাখতে হবে। অপ্রয়োজনীয়তা অপসারণ করা এক শ্রেণীর ত্রুটিগুলি সরিয়ে দেয়।- এক্সটেনসিবল: সি ++
<iostream>
মেকানিজম নতুন ব্যবহারকারী-সংজ্ঞায়িত প্রকারগুলিকে বিদ্যমান কোডটি ভঙ্গ না করে I / O'd করতে দেয়। বিশৃঙ্খলার কল্পনা করুন যদি প্রত্যেকে একই সাথে নতুনভাবে বেমানান "%" ক্ষেত্র যুক্ত করেprintf()
এবংscanf()
?!- উত্তরাধিকারী: সি ++
<iostream>
মেকানিজম যেমনstd::ostream
এবং এর মতো বাস্তব ক্লাস থেকে তৈরিstd::istream
। ভিন্ন<cstdio>
এরFILE*
, এই বাস্তব ক্লাস এবং অত: পর উত্তরাধিকারসূত্রে হয়। এর অর্থ আপনার কাছে অন্যান্য ব্যবহারকারীর দ্বারা সংজ্ঞায়িত জিনিস থাকতে পারে যা দেখতে দেখতে এবং স্ট্রিমের মতো কাজ করে, তবুও এটি আপনার পছন্দমতো অদ্ভুত এবং দুর্দান্ত কিছু করতে পারে। আপনি নিজেরাই জানেন না এমন ব্যবহারকারীদের দ্বারা লিখিত আই / ও কোডের জিলিয়ন লাইনগুলি আপনি স্বয়ংক্রিয়ভাবে ব্যবহার করতে পারবেন এবং তাদের আপনার "বর্ধিত স্ট্রিম" শ্রেণি সম্পর্কে জানার দরকার নেই।
অন্যদিকে, printf
পরিবর্তে এটি ব্যবহার ন্যায্যতা প্রতিপাদন করা হতে পারে উল্লেখযোগ্যভাবে দ্রুততর cout
মধ্যে খুব নির্দিষ্ট এবং সীমিত ক্ষেত্রে। সর্বদা প্রথম প্রোফাইল। (উদাহরণস্বরূপ, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /) দেখুন
printf()
এছাড়াও প্রসার্য হতে অনুমিত হয়। Udrepper.livej Journal.com/20948.html
printf
কোনও ক্ষমতা নেই। নন-পোর্টেবল লাইব্রেরি প্রক্রিয়াগুলি আইওস্ট্রিমের সম্পূর্ণ মানক এক্সটেনসিবিলিটির মতোই স্তরের স্তরে নয়।
লোকেরা প্রায়শই দাবি করে যে printf
এটি অনেক দ্রুত। এটি মূলত একটি পৌরাণিক কাহিনী। আমি কেবল নিম্নলিখিত পরীক্ষার সাথে এটি পরীক্ষা করেছি:
cout with only endl 1461.310252 ms
cout with only '\n' 343.080217 ms
printf with only '\n' 90.295948 ms
cout with string constant and endl 1892.975381 ms
cout with string constant and '\n' 416.123446 ms
printf with string constant and '\n' 472.073070 ms
cout with some stuff and endl 3496.489748 ms
cout with some stuff and '\n' 2638.272046 ms
printf with some stuff and '\n' 2520.318314 ms
উপসংহার: আপনি যদি কেবল নিউলাইনগুলি চান তবে ব্যবহার করুন printf
; অন্যথায়, cout
প্রায় হিসাবে দ্রুত, বা আরও দ্রুত। আরও বিস্তারিত আমার ব্লগে পাওয়া যাবে ।
স্পষ্টতই, আমি বলার চেষ্টা করছি না যে iostream
সবসময় এর চেয়ে ভাল হয় printf
; আমি কেবল এটি বলার চেষ্টা করছি যে কিছু সাধারণ, বিভ্রান্তিকর অনুমানের উপর ভিত্তি করে বন্য অনুমানের ভিত্তিতে আপনার বাস্তব তথ্যগুলির ভিত্তিতে একটি অবগত সিদ্ধান্ত নেওয়া উচিত।
আপডেট: আমি পরীক্ষার জন্য ব্যবহৃত পুরো কোডটি এখানে। g++
কোনও অতিরিক্ত বিকল্প ছাড়াই সংকলিত (সময় বাদে -lrt
)।
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
timespec d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
clock_gettime(CLOCK_REALTIME, &d_start);
}
~TimedSection() {
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
std::cerr << d_name << '\t' << std::fixed << duration << " ms\n";
}
};
int main() {
const int iters = 10000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
}
printf()
এবং এর মধ্যে গুরুত্বপূর্ণ পার্থক্যটি std::ostream
হ'ল প্রাক্তন সকল যুক্তিগুলিকে একক কলে আউটপুট দেয় যেখানে std::ostream
প্রত্যেকটির জন্য পৃথক কল অন্তর্ভুক্ত থাকে <<
। পরীক্ষাটি কেবল একটি যুক্তি এবং একটি নতুন লাইনকে আউটপুট দেয়, এজন্য আপনি পার্থক্যটি দেখতে পাচ্ছেন না।
printf
বিভিন্ন ফর্ম্যাটিং স্পেসিফায়ারের জন্য সহায়ক ফাংশনগুলির জন্য কভারগুলির নীচে প্রচুর কল করা যেতে পারে ... এটি, বা এটি একটি বিমূর্ত একঘেয়ে কাজ। এবং আবার, ইনলাইনিংয়ের কারণে, এটির গতিতে মোটেও কোনও পার্থক্য করা উচিত নয়।
sprintf
বা fprintf
এবং stringstream
বা fstream
।
এবং আমি উদ্ধৃতি :
উচ্চ স্তরের পদগুলিতে, প্রধান পার্থক্যগুলি হ'ল সুরক্ষা (সিএসডিডিওতে এটি নেই), কার্য সম্পাদন (বেশিরভাগ আইস্ট্রিমগুলি বাস্তবায়নগুলি সিএসডিডিওর চেয়ে ধীর হয়) এবং এক্সটেনসিবিলিটি (আইওস্ট্রিমগুলি কাস্টম আউটপুট লক্ষ্যমাত্রা এবং ব্যবহারকারীর সংজ্ঞায়িত ধরণের বিরামবিহীন আউটপুটকে মঞ্জুরি দেয়)।
একটি হ'ল প্রিন্ট করে এমন একটি ফাংশন। অন্যটি একটি অবজেক্ট যা স্টাডআউটে বেশ কয়েকটি সদস্য ফাংশন এবং operator<<
প্রিন্টের ওভারলোড সরবরাহ করে । আরও অনেক পার্থক্য রয়েছে যা আমি গণনা করতে পারি তবে আপনি কী পরে তা নিশ্চিত নই।
আমার জন্য, আসল পার্থক্যগুলি যা আমাকে 'প্রিন্টফ' এর পরিবর্তে 'কাউট'-এ যেতে দেয়:
1) << অপারেটর আমার ক্লাসের জন্য ওভারলোড করা যাবে।
2) আউটপুট স্ট্রিম সহজেই কোনও ফাইলে পরিবর্তিত হতে পারে: (: কপি পেস্ট :)
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
3) আমি কাউটকে আরও পাঠযোগ্য বলে মনে করি, বিশেষত যখন আমাদের অনেকগুলি পরামিতি থাকে।
ফর্ম্যাট করার বিকল্পগুলির সাথে একটি সমস্যাcout
options ডেটা ফর্ম্যাট করা (যথার্থতা, ন্যায়সঙ্গত ইত্যাদি) printf
আরও সহজ।
printf
কোনও ফাইলের পরিবর্তে এটির বদলে পরিবর্তন করতে পারেন fprintf
...
দুটি বিষয় যা অন্যথায় এখানে উল্লেখ করা হয়নি তা আমি উল্লেখযোগ্য বলে মনে করি:
1) cout
আপনি যদি ইতিমধ্যে এসটিএল ব্যবহার না করেন তবে প্রচুর লাগেজ বহন করে। এটি আপনার অবজেক্ট ফাইলে দ্বিগুণ কোড যুক্ত করে printf
। এটিও সত্য string
, এবং এটি আমার নিজের স্ট্রিং গ্রন্থাগারটি ব্যবহার করার প্রবণতার কারণ।
2) cout
অতিরিক্ত লোড <<
অপারেটরগুলি ব্যবহার করে , যা আমি দুর্ভাগ্যজনক বলে মনে করি। আপনি যদি <<
অপারেটরটিকে তার উদ্দেশ্যযুক্ত উদ্দেশ্যে (শিফট বাম দিকে) ব্যবহার করেন তবে এটি বিভ্রান্তি যুক্ত করতে পারে । অপারেটরগুলি তাদের উদ্দেশ্যযুক্ত ব্যবহারের জন্য স্পর্শকাতর উদ্দেশ্যে ব্যক্তিগতভাবে আমি ওভারলোড পছন্দ করি না।
নীচের লাইন: আমি যদি ইতিমধ্যে এসটিএল ব্যবহার করি তবে আমি cout
(এবং string
) ব্যবহার করব । অন্যথায়, আমি এটি এড়ানোর ঝোঁক।
আদিমগুলি সহ, আপনি সম্ভবত কোনটি ব্যবহার করেন তা সম্পূর্ণ বিবেচনা করে না। আমি বলি যে আপনি যখন জটিল অবজেক্টগুলি আউটপুট করতে চান তখন এটির দরকারীতা কোথায় পাওয়া যায়।
উদাহরণস্বরূপ, যদি আপনার কোনও ক্লাস থাকে,
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// output with printf
printf("%i, %i, %i\n", s.a, s.b, s.c);
// output with cout
cout << s << endl;
return 0;
}
এখন উপরেরটি এগুলি দুর্দান্ত মনে হচ্ছে না, তবে ধরা যাক আপনার কোডে একাধিক জায়গায় এটি আউটপুট করতে হবে। শুধু তাই নয়, আসুন আপনাকে একটি ক্ষেত্র যুক্ত করুন "int d"। কাউট সহ, আপনাকে কেবল একবারে এটি পরিবর্তন করতে হবে। তবে প্রিন্টফের সাহায্যে আপনাকে এটিকে সম্ভবত অনেক জায়গায় পরিবর্তন করতে হবে এবং কেবল এটিই নয়, আপনাকে কোনটি আউটপুট দিতে হবে তা নিজেকে স্মরণ করিয়ে দিতে হবে।
কৌতুকের সাহায্যে, আপনার কোডটি রক্ষণাবেক্ষণের জন্য ব্যয় করা অনেক সময় হ্রাস করতে পারবেন এবং এটিই নয় যে আপনি যদি নতুন অ্যাপ্লিকেশনটিতে "সামथিং" অবজেক্টটি পুনরায় ব্যবহার করেন, আপনাকে আউটপুট সম্পর্কে সত্যই চিন্তা করতে হবে না।
অবশ্যই আপনি রক্ষণাবেক্ষণের জন্য কিছুটা "ভাল" লিখতে পারেন:
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
void print() const { printf("%i, %i, %i\n", a, b, c); }
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// Output with printf
s.print(); // Simple as well, isn't it?
// Output with cout
cout << s << endl;
return 0;
}
এবং কাউট বনাম প্রিন্টফের কিছুটা বর্ধিত পরীক্ষা, 'ডাবল' এর পরীক্ষা যুক্ত করেছে, যদি কেউ আরও পরীক্ষা করতে চায় (ভিজ্যুয়াল স্টুডিও ২০০৮, এক্সিকিউটেবলের প্রকাশ সংস্করণ):
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
//timespec d_start;
clock_t d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
//clock_gettime(CLOCK_REALTIME, &d_start);
d_start = clock();
}
~TimedSection() {
clock_t end;
//clock_gettime(CLOCK_REALTIME, &end);
end = clock();
double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
*/
(double) (end - d_start) / CLOCKS_PER_SEC;
std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
}
};
int main() {
const int iters = 1000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
{
TimedSection s("cout with formatted double (width & precision once)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
std::cout.width(8);
for (int i = 0; i < iters; ++i)
std::cout << text << 8.315 << i << '\n';
}
{
TimedSection s("cout with formatted double (width & precision on each call)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
for (int i = 0; i < iters; ++i)
{ std::cout.width(8);
std::cout.precision(3);
std::cout << text << 8.315 << i << '\n';
}
}
{
TimedSection s("printf with formatted double");
for (int i = 0; i < iters; ++i)
printf("%8.3f%i\n", 8.315, i);
}
}
ফলাফল হলো:
cout with only endl 6453.000000 ms
cout with only '\n' 125.000000 ms
printf with only '\n' 156.000000 ms
cout with string constant and endl 6937.000000 ms
cout with string constant and '\n' 1391.000000 ms
printf with string constant and '\n' 3391.000000 ms
cout with some stuff and endl 9672.000000 ms
cout with some stuff and '\n' 7296.000000 ms
printf with some stuff and '\n' 12235.000000 ms
cout with formatted double (width & precision once) 7906.000000 ms
cout with formatted double (width & precision on each call) 9141.000000 ms
printf with formatted double 3312.000000 ms
endl
চেয়ে এত কম দক্ষ কেন '\n'
?
endl
এটি বাফারকে ফ্লাশ করে এবং \n
তা করে না, যদিও আমি নিশ্চিত নই যে এটির কারণটি অবশ্যই এটি।
আমি উল্লেখ করতে চাই যে আপনি যদি সি ++ তে থ্রেড নিয়ে খেলতে চান তবে আপনি যদি cout
কিছু আকর্ষণীয় ফলাফল পেতে পারেন।
এই কোডটি বিবেচনা করুন:
#include <string>
#include <iostream>
#include <thread>
using namespace std;
void task(int taskNum, string msg) {
for (int i = 0; i < 5; ++i) {
cout << "#" << taskNum << ": " << msg << endl;
}
}
int main() {
thread t1(task, 1, "AAA");
thread t2(task, 2, "BBB");
t1.join();
t2.join();
return 0;
}
// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x
এখন, আউটপুট সব পরিবর্তন হয়ে আসে। এটি বিভিন্ন ফলাফলও পেতে পারে, বেশ কয়েকবার কার্যকর করার চেষ্টা করুন:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
আপনি printf
এটি সঠিক পেতে ব্যবহার করতে পারেন , বা আপনি ব্যবহার করতে পারেন mutex
।
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
আনন্দ কর!
thread
এস আউটপুট গো বাদাম তৈরি করবেন না। আমি কেবল পুনরুত্পাদন করেছি এবং উভয় xyz
এবং ABC
আউটপুট খুঁজে পেয়েছি । সেখানে mangling হয়নি B / W ABC
যেমন ABABAB
।
cout
থ্রেডগুলির সাথে কীভাবে কাজ করে তা আমি জানি না তবে আমি নিশ্চিতভাবে জানি যে আপনি যে কোডটি দেখিয়ে দিচ্ছেন তা সেই ফলাফলগুলি নয় যা আপনি এই ফলাফলগুলি পেয়েছিলেন। আপনার কোডটি "ABC"
থ্রেড 1 এবং "xyz"
থ্রেড 2 এর জন্য স্ট্রিংটি কেটে দেয় তবে আপনার আউটপুটটি প্রদর্শন করে AAA
এবং BBB
। দয়া করে এটি ঠিক করুন, কারণ এখনই এটি বিভ্রান্তিকর।
cout<< "Hello";
printf("%s", "Hello");
উভয়ই মান মুদ্রণের জন্য ব্যবহৃত হয়। তাদের সম্পূর্ণ ভিন্ন বাক্য গঠন রয়েছে। সি ++ উভয়ই রয়েছে, সিটিতে কেবল প্রিন্টফ রয়েছে।
আমি বলতে চাই যে এক্সটেনসিবিলিটির অভাব printf
পুরোপুরি সত্য নয়:
সি তে, এটি সত্য। তবে সি তে, কোন বাস্তব ক্লাস নেই।
সি ++ এ, কাস্ট অপারেটরটিকে ওভারলোড করা সম্ভব, সুতরাং কোনও char*
অপারেটরকে ওভারলোড করা এবং এটি ব্যবহার করে printf
:
Foo bar;
...;
printf("%s",bar);
সম্ভব হতে পারে, যদি Foo ভাল অপারেটরটি ওভারলোড করে। অথবা আপনি যদি একটি ভাল পদ্ধতি তৈরি করেন। সংক্ষেপে, আমার জন্য printf
যেমন এক্সটেনসিবল cout
।
প্রযুক্তিগত যুক্তি আমি সি ++ টি স্ট্রিমের জন্য দেখতে পাচ্ছি (সাধারণভাবে ... কেবলমাত্র কোট নয়)) হ'ল:
Typesafety। (এবং, যাইহোক, আমি যদি একক মুদ্রণ করতে চাই তবে আমি '\n'
ব্যবহার করব putchar('\n')
... পোকা মারার জন্য আমি নিউক-বোম্ব ব্যবহার করব না))
সহজ শিখতে। (শেখার জন্য কোনও "জটিল" পরামিতি নেই, কেবল ব্যবহারের জন্য <<
এবং >>
অপারেটরগুলি)
স্থানীয়ভাবে কাজ করুন std::string
(কারণ printf
রয়েছে std::string::c_str()
তবে scanf
?)
জন্য printf
আমি দেখুন:
সহজ, বা কমপক্ষে খাটো (অক্ষরের পরিভাষায় লিখিত) জটিল ফর্ম্যাটিং। অনেক বেশি পঠনযোগ্য, আমার জন্য (স্বাদের বিষয়টি আমি অনুমান করি)।
ফাংশনটি কী করেছে তার আরও ভাল নিয়ন্ত্রণ (কতগুলি অক্ষর যেখানে লিখিত আছে এবং %n
ফর্ম্যাটারটি রয়েছে তা ফিরিয়ে দিন : "কিছুই মুদ্রিত নয় The আর্গুমেন্টটি অবশ্যই স্বাক্ষরিত ইন্টির দিকে নির্দেশক হওয়া উচিত, যেখানে এখন পর্যন্ত লেখা অক্ষরের সংখ্যা সংরক্ষণ করা হয়েছে।" ( প্রিন্টফ থেকে - সি ++ রেফারেন্স )
ভাল ডিবাগিং সম্ভাবনা। শেষ যুক্তি হিসাবে একই কারণে।
আমার ব্যক্তিগত পছন্দগুলি printf
(এবং scanf
) ফাংশনে যায়, মূলত আমি সংক্ষিপ্ত রেখাগুলি পছন্দ করি এবং প্রিন্টিং পাঠ্যের ক্ষেত্রে টাইপ সমস্যাগুলি এড়ানো সত্যিই কঠিন বলে আমি মনে করি না। সি-স্টাইলের ক্রিয়াকলাপগুলির সাথে কেবলমাত্র আমি আপত্তি জানাই std::string
এটি সমর্থিত নয়। আমরা একটি মধ্য দিয়ে যেতে char*
এটিকে দেবার আগে printf
(সঙ্গে std::string::c_str()
আমরা পড়েছি করতে চান তাহলে, কিন্তু কিভাবে লিখব?)
char*
ব্যবহৃত হবে না।
char*
জীবন এবং কত দিন, এবং ব্যবহারকারী-সংজ্ঞায়িত বিপদগুলি অন্তর্নিহিত কাস্ট।
আরও পার্থক্য: "প্রিন্টফ" একটি পূর্ণসংখ্যা মান প্রদান করে (মুদ্রিত অক্ষরের সংখ্যার সমান) এবং "কাউট" কোনও কিছুই ফেরায় না
এবং.
cout << "y = " << 7;
পারমাণবিক নয়।
printf("%s = %d", "y", 7);
পারমাণবিক।
cout typechecking সম্পাদন করে, প্রিন্টফ করে না।
এর সাথে আইওস্ট্রিমের সমতুল্য নেই "% d"
cout
কোনও জিনিস ফেরত দেয় না কারণ এটি একটি বস্তু, কোনও ফাংশন নয়। operator<<
কিছু ফেরত দেয় (সাধারণত এর বাম অপারেণ্ড, তবে একটি ত্রুটি থাকলে একটি মিথ্যা মান)। এবং printf
কলটি কোন অর্থে "পারমাণবিক"?
printf("%s\n",7);
%s
হয়?
printf
% s আর্গুমেন্টে একটি নাল টার্মিনেটেড স্ট্রিংয়ের একটি বৈধ পয়েন্টার থাকতে হবে। মেমরি পরিসীমা '7' (একটি পয়েন্টার) সাধারণত বৈধ হয় না; একটি বিভাজন ত্রুটি ভাগ্যবান হতে পারে। কিছু সিস্টেমে, '7' একটি কনসোলে প্রচুর আবর্জনা মুদ্রণ করতে পারে এবং প্রোগ্রামটি বন্ধ হওয়ার আগে আপনাকে এটির জন্য একদিন দেখতে হবে। অন্য কথায়, এটি সম্পর্কে একটি খারাপ জিনিস printf
। স্থিতিশীল বিশ্লেষণ সরঞ্জামগুলি এই সমস্যার অনেকগুলিই ধরতে পারে।
printf
টাইপচেকিং না করা অবস্থায়, আমি কখনও কখনও এমন সংকলক ব্যবহার করি নি যা আমাকে টাইপ ত্রুটি সম্পর্কে সতর্ক করে না printf
...
টিএল; ডিআর: উত্পাদিত মেশিন কোডের আকার , পারফরম্যান্স , পাঠযোগ্যতা এবং কোডিং সময় সম্পর্কিত এটিকে সহ অনলাইনে এলোমেলো মন্তব্যে বিশ্বাস করার আগে সর্বদা আপনার নিজের গবেষণা করুন।
আমি কোন বিশেষজ্ঞ নই। পারফরম্যান্স সমস্যার কারণে এম্বেড থাকা সিস্টেমে কীভাবে আমাদের সি ++ ব্যবহার করা এড়ানো উচিত সে সম্পর্কে কথা বলার জন্য আমি কেবলমাত্র দুই সহকর্মীকে শুনতে পেয়েছি। ভাল, যথেষ্ট আকর্ষণীয়, আমি একটি বাস্তব প্রকল্পের কাজের উপর ভিত্তি করে একটি মানদণ্ড করেছি।
এই কাজের মধ্যে, আমাদের র্যামে কিছু কনফিগারেশন লিখতে হয়েছিল। কিছুটা এইরকম:
কফি = গরম
চিনি =
দুধ নয় = স্তন
ম্যাক = এএ: বিবি: সিসি: ডিডি: ইই: এফএফ
এখানে আমার বেঞ্চমার্ক প্রোগ্রামগুলি (হ্যাঁ, আমি জানি ওপি প্রিন্টফ () সম্পর্কে জিজ্ঞাসা করেছিল, এফপ্রিন্টফ () নয়। সারমর্মটি ক্যাপচার করার চেষ্টা করুন এবং যাইহোক, ওপির লিঙ্কটি যেভাবেই হোক এফপ্রিন্টএফ () এ নির্দেশ করে।)
সি প্রোগ্রাম:
char coffee[10], sugar[10], milk[10];
unsigned char mac[6];
/* Initialize those things here. */
FILE * f = fopen("a.txt", "wt");
fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
fclose(f);
সি ++ প্রোগ্রাম:
//Everything else is identical except:
std::ofstream f("a.txt", std::ios::out);
f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
<< (int)mac[1] << ":"
<< (int)mac[2] << ":"
<< (int)mac[3] << ":"
<< (int)mac[4] << ":"
<< (int)mac[5] << endl;
f.close();
আমি তাদের উভয়কে 100,000 বার লুপ করার আগে পলিশ করার জন্য যথাসাধ্য চেষ্টা করেছি। ফলাফল এখানে:
সি প্রোগ্রাম:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
সি ++ প্রোগ্রাম:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
অবজেক্ট ফাইলের আকার:
C - 2,092 bytes
C++ - 3,272 bytes
উপসংহার: আমার খুব নির্দিষ্ট প্ল্যাটফর্মে , একটি খুব নির্দিষ্ট প্রসেসর সহ , লিনাক্স কার্নেলের একটি খুব নির্দিষ্ট সংস্করণ চালু করে, একটি প্রোগ্রাম চালানোর জন্য, যা একটি সুনির্দিষ্ট কার্য সম্পাদন করার জন্য, জিসিসির একটি নির্দিষ্ট সংস্করণ সহ সংকলিত একটি প্রোগ্রাম চালাতে , আমি বলব সি ++ পদ্ধতিটি আরও উপযুক্ত কারণ এটি উল্লেখযোগ্যভাবে দ্রুত চালিত হয় এবং আরও ভাল পাঠযোগ্যতা সরবরাহ করে। অন্যদিকে, সি ছোট পায়ের ছাপ দেয়, আমার মতে, এর অর্থ প্রায় কিছুই নয় কারণ প্রোগ্রামের আকারটি আমাদের উদ্বেগের নয়।
রিমবার, ওয়াইএমএমভি।
আমি প্রোগ্রামার নই, তবে আমি একজন মানবিক প্রকৌশলী হয়েছি। আমি মনে করি একটি প্রোগ্রামিং ভাষা শেখা, বুঝতে এবং ব্যবহার করা সহজ হওয়া উচিত এবং এর প্রয়োজন এটির একটি সহজ এবং ধারাবাহিক ভাষাগত কাঠামো। যদিও সমস্ত ভাষা প্রতীকী এবং এইভাবে, এর মূল ভিত্তিতে, স্বেচ্ছাসেবী, সেখানে সম্মেলন হয় এবং সেগুলি অনুসরণ করে ভাষা শিখতে এবং ব্যবহার সহজ করে তোলে।
সি ++ এবং ফাংশন (পরামিতি) হিসাবে লিখিত অন্যান্য ভাষায় প্রচুর ফাংশন রয়েছে, এটি একটি সিনট্যাক্স যা প্রাক কম্পিউটারের যুগে গণিতের কার্যকরী সম্পর্কের জন্য মূলত ব্যবহৃত হয়েছিল। printf()
এই বাক্য গঠনটি অনুসরণ করে এবং সি ++ র লেখকরা যদি ফাইল পড়তে এবং লেখার জন্য কোনও যুক্তিযুক্তভাবে আলাদা পদ্ধতি তৈরি করতে চান তবে তারা কেবল একই জাতীয় বাক্য গঠন ব্যবহার করে একটি ভিন্ন ফাংশন তৈরি করতে পারতেন।
পাইথনে আমরা অবশ্যই মোটামুটি মানক object.method
সিনট্যাক্স ব্যবহার করে মুদ্রণ করতে পারি , যেমন ভেরিয়েবল নাম.প্রিন্ট, যেহেতু ভেরিয়েবলগুলি বস্তু, তবে সি ++ এ সেগুলি হয় না।
আমি কাউট সিনট্যাক্সের পছন্দ নই কারণ << অপারেটর কোনও নিয়ম অনুসরণ করে না। এটি একটি পদ্ধতি বা ফাংশন, অর্থাৎ এটি একটি প্যারামিটার নেয় এবং এটিতে কিছু করে। তবে এটি লিখিত যেমন এটি একটি গাণিতিক তুলনা অপারেটর ছিল। এটি মানুষের কারণগুলির দিক থেকে একটি দুর্বল পদ্ধতি approach
printf
একটি ফাংশন যেখানে cout
একটি পরিবর্তনশীল হয়।
printf
একটি ফাংশন, তবে printf()
এটি একটি ফাংশন কল =)