স্ট্যান্ডিং :: স্ট্রিং সহ প্রিন্টফ?


157

আমার বোধগম্যতা হ'ল নেমস্পেসের stringসদস্য, stdতবে নিম্নলিখিতটি কেন ঘটে?

#include <iostream>

int main()
{
    using namespace std;

    string myString = "Press ENTER to quit program!";
    cout << "Come up and C++ me some time." << endl;
    printf("Follow this command: %s", myString);
    cin.get();

    return 0;
}

এখানে চিত্র বর্ণনা লিখুন

প্রতিবার প্রোগ্রামটি চললে, myStringউপরের আউটপুটে যেমন 3 টি অক্ষরের আপাতদৃষ্টিতে এলোমেলো স্ট্রিং প্রিন্ট করে।


8
কেবল আপনাকে জানাতেই, অনেক লোক এই বইটির সমালোচনা করে। যা আমি বুঝতে পারি, কারণ অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিংয়ের বিষয়ে তেমন কিছু নেই, তবে আমি মনে করি না যে এটি লোকেদের দাবি মতো খারাপ।
জেসি গুড

ouf! ভাল, আমি বইয়ের মাধ্যমে আমার পথ তৈরি করার সময় এটি মনে রাখা ভাল good আমি নিশ্চিত যে এটি কেবলমাত্র সি ++ বই হবে না যে আমি পরের বছর বা তার
পরেও পড়ব

সর্বাধিক সংকলক সতর্কতা ব্যবহার করা আপনার প্রশ্নের উত্তর দেবে - যখন সিসিটি সংকলন করে। এমএসভিসি কীভাবে এটি পরিচালনা করে - জানি না।
পিটার ভার্গা

উত্তর:


237

এটি printfনিরাপদ প্রকার নয় বলে এটি সংকলন করছে , কারণ এটি সি অর্থে 1 এ পরিবর্তনশীল যুক্তি ব্যবহার করে । printfএর জন্য কোনও বিকল্প নেই std::string, কেবল একটি সি-স্টাইলের স্ট্রিং। যা প্রত্যাশা করে তার স্থানে অন্য কিছু ব্যবহার করা আপনার পছন্দসই ফলাফল দেয় না। এটি আসলে অপরিবর্তিত আচরণ, তাই কিছুতেই ঘটতে পারে।

সবচেয়ে সহজ উপায় এই সমাধানের জন্য, যেহেতু আপনি সি ব্যবহার করছেন ++ সাধারণত মুদ্রণ সঙ্গে std::cout, যেহেতু std::stringসমর্থন করে মাধ্যমে অপারেটর ওভারলোডিং:

std::cout << "Follow this command: " << myString;

যদি কোনও কারণে আপনাকে সি-স্টাইলের স্ট্রিংটি বের করতে হয় তবে আপনি নাল-টার্মিনেটেড পাওয়ার c_str()পদ্ধতিটি ব্যবহার করতে পারেন । আপনার উদাহরণ ব্যবহার করে:std::stringconst char *

#include <iostream>
#include <string>
#include <stdio.h>

int main()
{
    using namespace std;

    string myString = "Press ENTER to quit program!";
    cout << "Come up and C++ me some time." << endl;
    printf("Follow this command: %s", myString.c_str()); //note the use of c_str
    cin.get();

    return 0;
}

আপনি যদি এমন কোনও ফাংশন চান যা পছন্দ করে printfতবে নিরাপদ টাইপ করে থাকে তবে ভেরিয়েডিক টেম্পলেটগুলি দেখুন (সি ++ 11, এমএসভিসি 12 হিসাবে সমস্ত বড় সংকলকগুলিতে সমর্থিত)। আপনি এখানে একটি উদাহরণ খুঁজে পেতে পারেন । স্ট্যান্ডার্ড লাইব্রেরিতে এর মতো বাস্তবায়িত হওয়ার মতো কিছুই আমার জানা নেই, তবে বিশেষভাবে বুস্টে থাকতে পারে boost::format


[1]: এর অর্থ হল যে আপনি যে কোনও সংখ্যক আর্গুমেন্ট পাস করতে পারেন, তবে ফাংশনটি আপনাকে এই আর্গুমেন্টগুলির সংখ্যা এবং প্রকারগুলি বলতে এটির উপর নির্ভর করে। ক্ষেত্রে printf, তার মানে এভাবে এনকোড টাইপ তথ্য সমেত একটি স্ট্রিং %dঅর্থ int। আপনি যদি প্রকার বা সংখ্যাটি সম্পর্কে মিথ্যা বলেন তবে ফাংশনটি জানার কোনও মানক উপায় নেই যদিও কিছু সংকলক আপনার মিথ্যা বলার সময় পরীক্ষা করার এবং সতর্কতা দেওয়ার ক্ষমতা রাখে।


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

43

দয়া করে ব্যবহার করবেন না printf("%s", your_string.c_str());

cout << your_string;পরিবর্তে ব্যবহার করুন। সংক্ষিপ্ত, সহজ এবং টাইপসেফ। আসলে, আপনি যখন সি ++ লিখছেন, আপনি সাধারণত printfসম্পূর্ণরূপে এড়াতে চান - এটি সি থেকে একটি অবশিষ্টাংশ যা সি ++ এ খুব কমই প্রয়োজন হয় বা দরকারী।

হিসেবে কেন আপনি ব্যবহার করা উচিত coutপরিবর্তে printf, কারণ অনেক। এখানে সর্বাধিক সুস্পষ্ট কয়েকটিগুলির নমুনা দেওয়া হল:

  1. যেমন প্রশ্নটি দেখায়, printfটাইপ-নিরাপদ নয়। আপনি যে ধরণের পাস করেন তা যদি রূপান্তর printfবর্ণনায় বর্ণিত বর্ণনার থেকে পৃথক হয় তবে স্ট্যাকের মধ্যে যা কিছু পাওয়া যায় তা ব্যবহার করার চেষ্টা করবে যেন এটি নির্দিষ্ট ধরণ, অপরিজ্ঞাত আচরণ করে। কিছু সংকলক কিছু পরিস্থিতিতে এ সম্পর্কে সতর্ক করতে পারে, তবে কিছু সংকলকরা একেবারে / করতে পারে না এবং কোনওটিই সব পরিস্থিতিতে হতে পারে না।
  2. printfএক্সটেনসিবল নয় আপনি কেবল এটিতে আদিম প্রকারগুলি পাস করতে পারেন। রূপান্তর নির্দিষ্টকরণের সেটগুলি এটি বুঝতে পারে এটি কার্যকরভাবে কার্যকরভাবে কোডেড, এবং আপনাকে আরও / অন্যদের যুক্ত করার উপায় নেই। বেশিরভাগ সু-লিখিত সি ++ এ সমস্যাগুলি সমাধানের দিকে লক্ষ্য করে প্রকারভেদগুলি প্রাথমিকভাবে প্রয়োগ করতে এই ধরণেরগুলি ব্যবহার করা উচিত।
  3. এটি শালীন বিন্যাসকে আরও অনেক কঠিন করে তোলে। একটি সুস্পষ্ট উদাহরণের জন্য, আপনি যখন লোকদের পড়ার জন্য সংখ্যা মুদ্রণ করছেন, আপনি সাধারণত প্রতি কয়েকটি অঙ্কে কয়েক হাজার বিভাজক সন্নিবেশ করতে চান। অঙ্কের সঠিক সংখ্যা এবং বিভাজক হিসাবে ব্যবহৃত অক্ষরগুলি পরিবর্তিত হয়, তবে এটিতেও coutএটি আবৃত থাকে। উদাহরণ স্বরূপ:

    std::locale loc("");
    std::cout.imbue(loc);
    
    std::cout << 123456.78;

    নামহীন লোকেল ("") ব্যবহারকারীর কনফিগারেশনের উপর ভিত্তি করে একটি লোকেল বাছাই করে। সুতরাং, আমার মেশিনে (মার্কিন ইংরাজির জন্য কনফিগার করা) এটি প্রিন্ট করে 123,456.78। যার কম্পিউটারের জন্য জার্মানি কনফিগার করা আছে তাদের জন্য (এটি) এমন কিছু মুদ্রণ হবে 123.456,78। এটির জন্য ভারতের জন্য কনফিগার করা কারও জন্য এটি মুদ্রণ করবে 1,23,456.78(এবং অবশ্যই আরও অনেকগুলি রয়েছে)। সঙ্গে printfআমি ঠিক পেতে একটি ফলাফল: 123456.78। এটি ধারাবাহিক, তবে সর্বত্র সর্বত্র এটি নিয়মিত ভুল । মূলত এর চারপাশে কাজ করার একমাত্র উপায় হ'ল আলাদাভাবে ফরম্যাটিং করা, তারপরে ফলাফলটিকে স্ট্রিং হিসাবে পাস করুন printf, কারণ printfকেবল কাজটি সঠিকভাবে কাজ করবে না

  4. যদিও তারা বেশ কমপ্যাক্ট, printfফর্ম্যাট স্ট্রিংগুলি বেশ অপঠনযোগ্য হতে পারে। এমনকি সি প্রোগ্রামারদের ব্যবহার করতে চায় মধ্যে printfপ্রতিদিন কার্যত, আমি অনুমান চাই অন্তত 99% জিনিষ আপ দেখুন কি নিশ্চিত হতে হবে #যে %#xমানে, এবং কিভাবে কি থেকে যে পৃথক #মধ্যে%#f (এবং হ্যাঁ, তারা সম্পূর্ণ ভিন্ন জিনিস বোঝায়) )।

11
@ দ্য ডার্কআইএন ১৯78৮: আপনি সম্ভবত ভুলে গেছেন #include <string>। ভিসি ++ এর শিরোলেখগুলিতে কিছু বিজোড় রয়েছে যা আপনাকে একটি স্ট্রিং সংজ্ঞায়িত করতে দেয়, তবে coutএটি <string>শিরোনাম না দিয়ে পাঠিয়ে দেয় না ।
জেরি কফিন

28
@ জেরি: কেবল উল্লেখ করতে চাই যে প্রিন্টফ ব্যবহার করা বড় ডেটার সাথে ডিল করার সময় কাউট ব্যবহারের চেয়ে অনেক বেশি দ্রুত। সুতরাং, দয়া করে এটি অকেজো বলে মনে করবেন না: ডি
প্রোগ্রামার

7
@Programmer: দেখুন stackoverflow.com/questions/12044357/... । সংক্ষিপ্তসার: বেশিরভাগ সময় coutধীর, কারণ আপনি std::endlযেখানে ব্যবহার করা উচিত সেখানে ব্যবহার করেছেন ।
জেরি কফিন

29
টিপিক্যাল সি ++ বিশেষজ্ঞ অহংকার। যদি প্রিন্টফের অস্তিত্ব থাকে তবে কেন এটি ব্যবহার করবেন না?
কুরোই নেকো

6
ঠিক আছে, চটজলদি মন্তব্যের জন্য দুঃখিত। তবুও, প্রিন্টফ ডিবাগিংয়ের জন্য বেশ কার্যকর এবং স্ট্রিমগুলি যদিও আরও বেশি শক্তিশালী, ত্রুটি রয়েছে যে কোডটি আসল আউটপুট সম্পর্কে কোনও ধারণা দেয় না। বিন্যাসিত আউটপুট জন্য, মুদ্রণযন্ত্র এখনও একটি কার্যকর বিকল্প, এবং এটি উভয় সিস্টেম আরও ভাল সহযোগিতা করতে পারে না লজ্জাজনক। অবশ্যই আমার মতামত.
কুরোই নেকো



1

মূল কারণটি সম্ভবত সি ++ স্ট্রিং এমন একটি কাঠামো যা একটি বর্তমান দৈর্ঘ্যের মান অন্তর্ভুক্ত করে কেবল 0 বাইট দ্বারা সমাপ্ত অক্ষরের ক্রমের ঠিকানা নয়। প্রিন্টফ এবং তার আত্মীয়স্বজনগুলি স্ট্রাক্ট নয়, এই জাতীয় ক্রমটি আবিষ্কার করার আশা করে এবং তাই সি ++ স্ট্রিংগুলিতে বিভ্রান্ত হয়।

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

জিএনইউ প্রকল্প যদি প্রিন্টফ পরিবারকে তাদের জি ++ এক্সটেনশনে যুক্ত করে তবে এটি বেশ সুন্দর হবে।


1

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

আপনার পরিস্থিতির জন্য, আইডি cout ব্যবহার করার পরামর্শ দেয় কারণ এটি ব্যবহার করা আরও বেশি সুবিধাজনক। যদিও, আমি যুক্তি দিয়ে বলব যে প্রিন্টফটি জানা ভাল।


1

printfএকটি পরিবর্তনশীল সংখ্যক আর্গুমেন্ট গ্রহণ করে। এগুলিতে কেবল সাধারণ ওল্ড ডেটা (পিওডি) প্রকার থাকতে পারে। কোড যা POD ব্যতীত অন্য কিছু পাস করে printfকেবল সংকলন করে কারণ সংকলক ধরে নেয় আপনি আপনার ফর্ম্যাটটি সঠিক পেয়েছেন। %sএর মানে হল যে সম্পর্কিত আর্গুমেন্টটি a এর পয়েন্টার হিসাবে বিবেচিত হবে char। আপনার ক্ষেত্রে এটি একটি std::stringনা const char*printfএটি জানে না কারণ আর্গুমেন্টের ধরণটি হারিয়ে যায় এবং ফর্ম্যাট প্যারামিটার থেকে পুনরুদ্ধার হওয়ার কথা। সেই std::stringযুক্তিটিকে const char*ফলাফলের পয়েন্টারে পরিণত করার সময় আপনার পছন্দসই সি স্ট্রিংয়ের পরিবর্তে মেমরির কিছু অপ্রাসঙ্গিক অঞ্চলকে নির্দেশ করা হবে। যে কারণে আপনার কোড গীবত ছাপে।

ফর্ম্যাটযুক্ত পাঠ্য প্রিন্ট করার জন্য যদিও printfএটি একটি দুর্দান্ত পছন্দ , (বিশেষত যদি আপনার প্যাডিং থাকে) তবে আপনি যদি সংকলক সতর্কতা সক্ষম না করেন তবে তা বিপজ্জনক হতে পারে। সর্বদা সতর্কতা সক্ষম করুন কারণ এর পরে ভুলগুলি সহজেই এড়ানো যায়। পরিবার std::coutযদি printfআরও দ্রুত এবং সুন্দরভাবে একই কাজ করতে পারে তবে আনাড়ি প্রক্রিয়াটি ব্যবহার করার কোনও কারণ নেই । কেবলমাত্র নিশ্চিত হয়ে নিন যে আপনি সমস্ত সতর্কতা ( -Wall -Wextra) সক্ষম করেছেন এবং আপনি ভাল হবেন। আপনি যদি নিজের নিজস্ব কাস্টম printfবাস্তবায়ন ব্যবহার করেন তবে আপনাকে সেই __attribute__প্রক্রিয়াটি দিয়ে তা ঘোষণা করা উচিত যা সংকলককে প্রদত্ত পরামিতিগুলির বিপরীতে বিন্যাসের স্ট্রিং চেক করতে সক্ষম করে

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