লুপ অবস্থায় ব্যবহৃত হলে স্ট্রেন একাধিকবার গণনা করা যাবে?


109

আমি নিশ্চিত নন যে নীচের কোডটি অনর্থক গণনার কারণ হতে পারে, বা এটি সংকলক-নির্দিষ্ট?

for (int i = 0; i < strlen(ss); ++i)
{
    // blabla
}

হবে strlen()যখন প্রত্যেক সময় গণনা করা iবাড়ে?


14
আমি অনুমান করতে যাচ্ছি যে একটি পরিশীলিত অপ্টিমাইজেশন ছাড়া এটি সনাক্ত করতে পারে যে 'এস' কখনই লুপে পরিবর্তন হয় না, তবে হ্যাঁ। সংকলন করা সেরা, এবং সমাবেশটি দেখুন।
মেরিকোওয়া

6
এটি সংযোজকটির উপর, অপ্টিমাইজেশনের স্তরের এবং ssলুপের ভিতরে আপনি (সম্ভবত) কী করতে পারেন তার উপর নির্ভর করে ।
হিস্তো ইলিভ

4
যদি সংকলক প্রমাণ করতে পারে যা ssকখনই সংশোধিত হয় না, এটি লুপের বাইরে গণনা উত্তোলন করতে পারে।
ড্যানিয়েল ফিশার

10
@ মাইক: "স্ট্র্লেন ঠিক কী করে তার সংকলন-সময়ের বিশ্লেষণ প্রয়োজন" - স্ট্রেন সম্ভবত একটি অন্তর্নিহিত, এক্ষেত্রে অপ্টিমাইজার এটি জানে কী করে।
স্টিভ জেসোপ

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

উত্তর:


138

হ্যাঁ, strlen()প্রতিটি পুনরাবৃত্তির উপর মূল্যায়ন করা হবে। এটি সম্ভব যে, আদর্শ পরিস্থিতিতে অপটিমাইজারটি অনুমান করতে সক্ষম হতে পারে যে মানটি পরিবর্তন হবে না, তবে আমি ব্যক্তিগতভাবে তার উপর নির্ভর করব না।

আমি ভালো কিছু করব

for (int i = 0, n = strlen(ss); i < n; ++i)

বা সম্ভবত

for (int i = 0; ss[i]; ++i)

যতক্ষণ স্ট্রিং পুনরাবৃত্তির সময় দৈর্ঘ্য পরিবর্তন করতে যাচ্ছে না। যদি এটি হতে পারে তবে আপনাকে strlen()প্রতিটি সময় কল করতে হবে বা আরও জটিল যুক্তির মাধ্যমে পরিচালনা করতে হবে।


14
আপনি যদি জানেন যে আপনি স্ট্রিংটি চালাচ্ছেন না, তবে এটি মূলত লুপটি যে strlenকোনও উপায়ে সম্পাদন করা হবে since
mlibby

26
@ ডাল: যদি স্ট্রিংটি সংক্ষিপ্ত হয়ে যেতে পারে তবে উভয়টিই ভুল।
মাইক সিমুর

3
@ ডাল: আপনি যদি স্ট্রিং পরিবর্তন করছেন তবে লুপের জন্য সম্ভবত প্রতিটি চরিত্রের পুনরাবৃত্তি করার সেরা উপায় নয়। আমি মনে করি কিছুক্ষণের জন্য লুপটি সূচক কাউন্টারটি পরিচালনা করতে আরও সরাসরি এবং সহজ।
mlibby

2
আদর্শ পরিস্থিতিতে লিনাক্সের অধীনে জিসিসি সহ সংকলন অন্তর্ভুক্ত রয়েছে, যেখানে strlenচিহ্নিত করা হয়েছে__attribute__((pure)) সংকলককে একাধিক কলকে এলিডে প্রবেশ করার অনুমতি । জিসিসির বৈশিষ্ট্য
ডেভিড রদ্রিগেজ -

6
দ্বিতীয় সংস্করণটি আদর্শ এবং সর্বাধিক প্রতিচ্ছবিযুক্ত ফর্ম। এটি আপনাকে দু'বারের পরিবর্তে একবারে স্ট্রিং পার করতে সহায়তা করে, যা দীর্ঘ স্ট্রিংয়ের জন্য আরও ভাল পারফরম্যান্স (বিশেষত ক্যাশে সুসংহত) করবে।
আর .. গীটহাব বন্ধ করুন ICE

14

হ্যাঁ, প্রতিবার আপনি লুপটি ব্যবহার করবেন। তারপরে এটি প্রতিবার স্ট্রিংয়ের দৈর্ঘ্য গণনা করবে। সুতরাং এটির মতো ব্যবহার করুন:

char str[30];
for ( int i = 0; str[i] != '\0'; i++)
{
//Something;
}

উপরের কোডে প্রতিটি বার লুপ একটি চক্র শুরু করলে লোকেশনে str[i]স্ট্রিংয়ের একটি নির্দিষ্ট চরিত্রটি যাচাই করে i, সুতরাং এটি কম স্মৃতি গ্রহণ করবে এবং আরও কার্যকর।

আরও তথ্যের জন্য এই লিঙ্কটি দেখুন ।

নীচের কোডটিতে প্রতিবার লুপটি চলে strlen পুরো স্ট্রিংয়ের দৈর্ঘ্য গণনা করবে যা কম দক্ষ, বেশি সময় নেয় এবং আরও মেমরি নেয়।

char str[];
for ( int i = 0; i < strlen(str); i++)
{
//Something;
}

3
আমি "[এটি] আরও দক্ষ" এর সাথে একমত হতে পারি, তবে কম স্মৃতি ব্যবহার করব? কল করার সময় কেবলমাত্র মেমরি ব্যবহারের পার্থক্যটি কল স্ট্যাকের মধ্যে থাকতে পারে strlenএবং আপনি যদি এই আঁটসাঁট কাজটি চালিয়ে যাচ্ছেন তবে আপনার সম্ভবত অন্য কয়েকটি ফাংশন কলগুলিও এলিডিংয়ের বিষয়ে চিন্তা করা উচিত ...
একটি সিভিএন

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

1
আমি নিশ্চিত না যে এটি আসলে প্রচুর অর্থবোধ করে। স্ট্রলিনের খুব নির্বুদ্ধ বাস্তবায়ন এমন কিছু হবে যা আপনার উত্তরটিতে কোডটিতে int strlen(char *s) { int len = 0; while(s[len] != '\0') len++; return len; }আপনি যা করছেন ঠিক তা হ'ল। আমি যুক্তি দিচ্ছি না যে স্ট্রিংয়ের দ্বিগুণ হওয়ার চেয়ে একবারের চেয়ে বার বার হওয়া আরও বেশি সময়- দক্ষ, তবে আমি এক বা অন্যটিকে কম বা বেশি স্মৃতি ব্যবহার করতে দেখছি না। অথবা আপনি স্ট্রিংয়ের দৈর্ঘ্য ধরে রাখতে ব্যবহৃত ভেরিয়েবলের কথা উল্লেখ করছেন?
সিভিএন

@ মাইকেলKjörling দয়া করে উপরের সম্পাদিত কোড এবং লিঙ্কটি দেখুন। এবং মেমরি হিসাবে- প্রতিবার লুপটি সঞ্চালিত প্রতিটি মানকে পুনরাবৃত্তি করে মেমরির মধ্যে এবং 'স্ট্র্লেন' ক্ষেত্রে এটি স্ট্রিংটিকে বারবার গণ্য করা হয় এবং এটি সংরক্ষণ করার জন্য আরও মেমরির প্রয়োজন হয়। এবং এটি জাভা থেকে ভিন্ন, সি ++ এর কোনও "আবর্জনা সংগ্রাহক" নেই। তাহলে আমিও ভুল হতে পারি। সি ++ এ "আবর্জনা সংগ্রাহক" এর অনুপস্থিতি সম্পর্কিত লিঙ্কটি দেখুন ।
কোডডেক্সটার 21

1
@ aashis2s জঞ্জাল সংগ্রহকারীর অভাব যখন গাদাতে অবজেক্ট তৈরি করে কেবল তখনই ভূমিকা পালন করে। স্ট্যাকের অবজেক্টগুলি স্কোপ এবং শেষ হওয়ার সাথে সাথে ধ্বংস হয়ে যায়।
ইক্কে

9

একটি ভাল সংকলক প্রতিবার এটি গণনা করতে পারে না, তবে আমি মনে করি না আপনি নিশ্চিত হতে পারেন যে প্রতি সংকলক এটি করে।

এছাড়াও, সংকলকটি জানতে হবে, এটি strlen(ss)পরিবর্তন হয় না। যদি ssএটি পরিবর্তন না করা হয় তবেই এটি সত্যforলুপে ।

উদাহরণস্বরূপ, আপনি যদি লুপটিতে কেবল পঠনযোগ্য ফাংশন ব্যবহার ssকরেন forতবে ss-পরিমিতি হিসাবে ঘোষণা করেন না const, সংকলক এমনকি এটিও জানতে পারে না যে ssলুপে পরিবর্তন হয়নি strlen(ss)এবং প্রতিটি পুনরাবৃত্তিতে গণনা করতে হবে ।


3
+1: কেবল লুপে ssপরিবর্তন করা উচিত নয় for; এটি লুপে ডাকা কোনও ফাংশন দ্বারা অ্যাক্সেসযোগ্য এবং পরিবর্তিত হওয়া উচিত নয় (হয় কারণ এটি একটি আর্গুমেন্ট হিসাবে পাস হয়েছে, বা এটি বৈশ্বিক পরিবর্তনশীল বা একটি ফাইল-স্কোপ ভেরিয়েবলের কারণে)। কনস্ট-কোয়ালিফিকেশন এছাড়াও একটি কারণ হতে পারে।
জোনাথন লেফলার

4
আমার মনে হয় যে সংকলকটি জানতে পারে যে 'এস' পরিবর্তন হয় না highly 'Ss' এর ভিতরে স্মৃতিতে নির্দেশ করে এমন বিপথগামী পয়েন্টার থাকতে পারে যা
সংকলকটির

জোনাথন ঠিক বলেছেন, একটি স্থানীয় কন্স স্ট্রিংই এই সংকলকের পক্ষে নিশ্চিত হওয়ার একমাত্র উপায় হতে পারে যে 'এস' এর পরিবর্তনের কোনও উপায় নেই।
মেরিকোওয়া

2
@ মেরিকওয়া: সত্যই, এটি restrictসি 99 এর জন্য অন্যতম একটি জিনিস ।
স্টিভ জেসোপ

4
আপনার শেষ প্যারা সম্পর্কিত: আপনি যদি ssফর-লুপটিতে কেবল পঠন ফাংশনটিতে কল করেন তবে তার পরামিতিটি ঘোষিত হলেওconst char* , সংকলকটিকে এখনও দৈর্ঘ্য পুনরায় গণনা করতে হবে যদি না হয় (ক) এটি জানে না যে ssকোনও কনস্টেন্ট অবজেক্টের দিকে নির্দেশ করে, কেবলমাত্র পয়েন্টার-টু-কনস্টেন্ট হওয়ার বিপরীতে, বা (খ) এটি ফাংশনটি ইনলাইন করতে পারে বা অন্যথায় দেখতে পারে যে এটি কেবল পঠনযোগ্য। একটি গ্রহণ const char*প্যারামিটার না একটি প্রতিশ্রুতি সংশোধন করতে না ডেটাতে উল্লেখ, কারণ এটি কাস্ট করতে বৈধ char*এবং যে বস্তুর পরিবর্তিত const নয় এবং একটি স্ট্রিং আক্ষরিক নয় উপলব্ধ পরিবর্তন করুন।
স্টিভ জেসোপ

4

যদি ssটাইপ হয় const char *এবং আপনি constকম্পকায়ার কেবল কল করতে পারে লুপ মধ্যে ness দূরে নিক্ষেপ নাstrlen তবে অপটিমাইজেশন চালু থাকলে সংকলকটি একবার । তবে এটি অবশ্যই এমন আচরণ নয় যা গণনা করা যায়।

আপনার strlenফলাফলটি পরিবর্তনশীলে সংরক্ষণ করা উচিত এবং লুপটিতে এই পরিবর্তনশীলটি ব্যবহার করা উচিত । আপনি যা করছেন তার উপর নির্ভর করে যদি আপনি কোনও অতিরিক্ত ভেরিয়েবল তৈরি করতে না চান তবে লুপটি উল্টিয়ে পিছনের দিকে ফিরে যেতে আপনি দূরে সরে যেতে পারেন।

for( auto i = strlen(s); i > 0; --i ) {
  // do whatever
  // remember value of s[strlen(s)] is the terminating NULL character
}

1
একেবারেই ফোন strlenকরা ভুল । আপনি শেষ আঘাত না হওয়া পর্যন্ত লুপ।
আর .. গীটহাব বন্ধ হেল্পিং আইসিসি

i > 0? i >= 0এখানে কি হওয়া উচিত নয় ? ব্যক্তিগতভাবে, আমি strlen(s) - 1স্ট্রিংটি পিছনের দিকে পুনরুক্তি করেও শুরু করব , তবে সমাপ্তির \0কোনও বিশেষ বিবেচনার প্রয়োজন নেই।
একটি সিভিএন

2
@ মাইকেলKjörling i >= 0কেবল তখনই কাজ করে যদি আপনি আরম্ভ করেন strlen(s) - 1তবে তারপরে যদি আপনার শূন্য দৈর্ঘ্যের একটি স্ট্রিং থাকে তবে প্রাথমিক মান নিমজ্জিত হয়
প্রিটোরিয়ান

@ প্রিটরিয়ান, শূন্য দৈর্ঘ্যের স্ট্রিংয়ের ভাল পয়েন্ট। আমি আমার মন্তব্য লেখার সময় আমি সেই মামলাটি বিবেচনা করি নি। সি ++ i > 0প্রাথমিক লুপ এন্ট্রিতে অভিব্যক্তিটি মূল্যায়ন করে ? যদি এটি না হয় তবে আপনি ঠিক বলেছেন, শূন্য দৈর্ঘ্যের কেসটি অবশ্যই লুপটি ভেঙে দেবে। যদি এটি হয় তবে আপনি "সহজভাবে" একটি স্বাক্ষরিত i== -1 <0 পান যাতে শর্তাধীন থাকলে লুপ এন্ট্রি নেই i >= 0
একটি সিভিএন

@ মাইকেলকিজারলিং হ্যাঁ, প্রথমবারের জন্য লুপটি কার্যকর করার আগে প্রস্থান শর্তটি মূল্যায়ন করা হয়। strlenএর রিটার্নের ধরনটি স্বাক্ষরবিহীন, তাই (strlen(s)-1) >= 0শূন্য দৈর্ঘ্যের স্ট্রিংয়ের জন্য সত্য হিসাবে মূল্যায়ন করে।
প্রিটোরিয়ান

3

সাধারণত হ্যাঁ, strlen() প্রতিটি পুনরাবৃত্তি জন্য কল করা হবে বলে আশা করা হচ্ছে।

যাইহোক আমি কিছু চতুর সংকলক অপ্টিমাইজেশনের উপস্থিতির সম্ভাবনাটিকে অস্বীকার করতে চাই না, এটি প্রথমটির পরে স্ট্র্লেন () এর পর পরের কলটিকে অপ্টিমাইজ করবে।


3

এটির সম্পূর্ণ প্রাকটিক কোডটি forলুপের প্রতিটি পুনরাবৃত্তিতে কার্যকর করা হবে on কলটির ফলাফলটি স্মরণে রাখতে strlen(ss)কমপাইলারের কমপক্ষে এটি জানতে হবে

  1. ফাংশনটি strlenপার্শ্ব প্রতিক্রিয়া মুক্ত ছিল
  2. দ্বারা চিহ্নিত স্মৃতিটি ssলুপের সময়কালের জন্য পরিবর্তিত হয় না

সংকলক এই দুটি জিনিসই জানে না এবং তাই প্রথম কলের ফলাফলটি নিরাপদে স্মরণ করতে পারে না


আচ্ছা এটা পারে স্ট্যাটিক বিশ্লেষণের সঙ্গে সেগুলো জানি, কিন্তু আমি মনে করি আপনার পয়েন্ট যে এই ধরনের বিশ্লেষণ বর্তমানে কোনো সি কম্পাইলার মধ্যে ++, বাস্তবায়িত হয়নি হ্যাঁ হয়?
GManNickG

@GManNickG এটি নিশ্চিতভাবে # 1 প্রমাণ করতে পারে তবে # 2 আরও শক্ত is একক থ্রেডের জন্য হ্যাঁ এটি অবশ্যই এটি প্রমাণ করতে পারে তবে বহু-থ্রেড পরিবেশের জন্য নয়।
জারেডপাড়

1
সম্ভবত আমি একগুঁয়ে হয়ে যাচ্ছি কিন্তু আমি মনে করি বহুবিবাহিত পরিবেশেও দ্বিতীয় নম্বরে সম্ভব, তবে অবশ্যই বুনো শক্তিশালী অনুক্রম সিস্টেম ছাড়া না। শুধু এখানে যদিও সংগীত; অবশ্যই কোনও বর্তমান সি ++ কম্পাইলারের সুযোগ ছাড়িয়ে।
GManNickG

@ জিএমএনএনজিজি আমি মনে করি না যে এটি সি / সি ++ তে থাকা সম্ভব। আমি খুব সহজে এর ঠিকানা লুকিয়ে পারে ssএকটি মধ্যে size_tঅথবা এটি ভাগ বিভিন্ন মাঝে byteমান। আমার আঁকাবাঁকা থ্রেড তারপর ঠিক যে ঠিকানা এবং কম্পাইলার মধ্যে লিখুন বাইট বুঝতে এটি এর সাথে সম্পর্কিত এর জানা উপায় আছে হতো ss
জারেডপাড়

1
@ জেয়ার্ডপাড়: ধাক্কা দেওয়ার জন্য দুঃখিত, আপনি দাবি করতে int a = 0; do_something(); printf("%d",a);পারেন যে সেই ভিত্তিটি do_something()আপনার অনুকূলিতকরণের মতো কাজ করতে পারে বা এই স্ট্যাকটিকে ব্যাক আপ করতে পারে এবং aইচ্ছাকৃতভাবে সংশোধন করতে পারে that সত্যিকার অর্থে, do_something(); printf("%d",0);জিসিসি 4.5 এটি -O3 এর সাথে অনুকূল করে তোলে
স্টিভ

2

হ্যাঁ । যখন আমি বৃদ্ধি পাই তখন প্রতিটি সময়ে স্ট্রেন গণনা করা যাইবে।

যদি আপনি লুপের সাথে এসএস পরিবর্তন না করে থাকেন তবে এটি যুক্তিকে প্রভাবিত করবে না অন্যথায় এটি প্রভাবিত করবে।

নিম্নলিখিত কোড ব্যবহার করা নিরাপদ।

int length = strlen(ss);

for ( int i = 0; i < length ; ++ i )
{
 // blabla
}

2

হ্যাঁ, strlen(ss)প্রতিটি প্রতিটি পুনরাবৃত্তিতে দৈর্ঘ্য গণনা করবে। আপনি যদি ssকোনও উপায়ে বাড়িয়ে দিচ্ছেন এবং আরও বাড়িয়ে দিচ্ছেন i; অসীম লুপ হবে।


2

হ্যাঁ, strlen()ফাংশনটি প্রতিবার ডাকা হয় লুপটি মূল্যায়ন ।

আপনি যদি দক্ষতাটি উন্নত করতে চান তবে সর্বদা স্থানীয় ভেরিয়েবলগুলিতে সংরক্ষণ করার কথা মনে রাখবেন ... এতে সময় লাগবে তবে এটি খুব দরকারী ..

আপনি নীচের মত কোড ব্যবহার করতে পারেন:

String str="ss";
int l = strlen(str);

for ( int i = 0; i < l ; i++ )
{
    // blablabla
}


2

আজকাল সাধারণ নয় তবে 20 বছর আগে 16 বিট প্ল্যাটফর্মে, আমি এটির পরামর্শ দিই:

for ( char* p = str; *p; p++ ) { /* ... */ }

আপনার সংকলক অপ্টিমাইজেশনে খুব স্মার্ট না হলেও, উপরের কোডটি এখনও ভাল অ্যাসেমব্লিং কোডে আসতে পারে।


1

হ্যাঁ. পরীক্ষাটি জানে না যে এসএস লুপের অভ্যন্তরে পরিবর্তন হয় না। যদি আপনি জানেন যে এটি পরিবর্তন হবে না তবে আমি লিখব:

int stringLength = strlen (ss); 
for ( int i = 0; i < stringLength; ++ i ) 
{
  // blabla 
} 

1

হুমকি, এমনকি, এমনকি আদর্শ পরিস্থিতিতে, অভিশাপ!

আজ (জানুয়ারী 2018), এবং গিগি 7.3 এবং ঝাঁকুনি 5.0, যদি আপনি সংকলন করেন:

#include <string.h>

void bar(char c);

void foo(const char* __restrict__ ss) 
{
    for (int i = 0; i < strlen(ss); ++i) 
    {
        bar(*ss);
    }
}    

তাহলে আমাদের আছে:

  • ss একটি ধ্রুবক পয়েন্টার।
  • ss চিহ্নিত করা আছে __restrict__
  • লুপ বডি কোনওভাবেই নির্দেশিত মেমরিটিকে স্পর্শ করতে পারে না ss(ভাল, যদি না এটি লঙ্ঘন করে __restrict__)।

এবং এখনও , উভয় সংকলক এই লুপটির strlen() প্রতিটি একক পুনরাবৃত্তি সম্পাদন করে । অ্যামেজিং।

এর অর্থ হ'ল @ প্রেটরিওরিয়ান এবং @ জেয়ার্ডপাড়ের প্রবণতা / ইচ্ছাকৃত চিন্তাভাবনাটি প্যানেল না।


0

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


0

হ্যাঁ.

strlen() প্রতিবার গণনা করা হয় যখন i বৃদ্ধি হয় এবং অনুকূলিত হয় না।

নীচের কোডগুলি দেখায় যে সংকলকটি কেন অপ্টিমাইজ করা উচিত নয় strlen()

for ( int i = 0; i < strlen(ss); ++i )
{
   // Change ss string.
   ss[i] = 'a'; // Compiler should not optimize strlen().
}

আমি মনে করি যে নির্দিষ্ট পরিবর্তনটি এসএসের দৈর্ঘ্যকে কখনই পরিবর্তন করে না, কেবল এটির বিষয়বস্তু, সুতরাং (সত্যই সত্যই একটি চতুর) সংকলক এখনও অনুকূলিত করতে পারে strlen
ড্যারেন কুক

0

আমরা এটি সহজেই পরীক্ষা করতে পারি:

char nums[] = "0123456789";
size_t end;
int i;
for( i=0, end=strlen(nums); i<strlen(nums); i++ ) {
    putchar( nums[i] );
    num[--end] = 0;
}

লুপটি পুনরায় চালু করার আগে প্রতিটি পুনরাবৃত্তির পরে লুপের শর্তটি মূল্যায়ন করে।

দৈর্ঘ্যের স্ট্রিংগুলি পরিচালনা করতে আপনি যে ধরণের ব্যবহার করেন সে সম্পর্কেও যত্নবান হন। এটি এমনটি হওয়া উচিত size_tযা স্টুডিও হিসাবে সংজ্ঞায়িত হয়েছে unsigned int। এটি তুলনা করা এবং কাস্ট করা intকিছু গুরুতর দুর্বলতার সমস্যার কারণ হতে পারে।


0

ভাল, আমি লক্ষ্য করেছি যে কেউ বলছে যে এটি কোনও "চালাক" আধুনিক সংকলক দ্বারা ডিফল্টরূপে অনুকূলিত হয়েছে। উপায় দ্বারা অপ্টিমাইজেশন ছাড়া ফলাফল দেখুন। আমি চেষ্টা করেছি:
ন্যূনতম সি কোড:

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

int main()
{
 char *s="aaaa";

 for (int i=0; i<strlen(s);i++)
  printf ("a");
 return 0;
}

আমার সংকলক: g ++ (উবুন্টু / লিনারো 4.6.3-1ubuntu5) 4.6.3
সমাবেশ কোড উত্পন্ন করার জন্য কমান্ড: g ++ -S -masm = ইন্টেল টেস্ট কোডপিপি

Gotten assembly code at the output:
    ...
    L3:
mov DWORD PTR [esp], 97
call    putchar
add DWORD PTR [esp+40], 1
    .L2:
     THIS LOOP IS HERE
    **<b>mov    ebx, DWORD PTR [esp+40]
mov eax, DWORD PTR [esp+44]
mov DWORD PTR [esp+28], -1
mov edx, eax
mov eax, 0
mov ecx, DWORD PTR [esp+28]
mov edi, edx
repnz scasb</b>**
     AS YOU CAN SEE it's done every time
mov eax, ecx
not eax
sub eax, 1
cmp ebx, eax
setb    al
test    al, al
jne .L3
mov eax, 0
     .....

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

0

প্রিটোরিয়ানের উত্তরের ব্যাখ্যা দিয়ে আমি নিম্নলিখিতটি সুপারিশ করি:

for( auto i = strlen(s)-1; i > 0; --i ) {foo(s[i-1];}
  • autoকারণ আপনি কী ধরণের স্ট্রলেন রিটার্নের বিষয়ে যত্ন নিতে চান না। একটি সি ++ 11 সংকলক (উদাহরণস্বরূপ gcc -std=c++0x, সম্পূর্ণ সি ++ 11 নয় তবে স্বয়ংক্রিয় ধরণের কাজ করে) আপনার জন্য এটি করবে।
  • i = strlen(s)আপনি তুলনা করতে চাই কারণ 0(নীচে দেখুন)
  • i > 0 কারণ 0 এর সাথে তুলনা করা (সামান্য) অন্য যে কোনও সংখ্যার সাথে তুলনা করে দ্রুত।

অসুবিধাটি হ'ল i-1স্ট্রিং অক্ষরগুলি অ্যাক্সেস করতে আপনাকে ব্যবহার করতে হবে ।

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