সংকলন সময়ে সি স্ট্রিংয়ের গণনা দৈর্ঘ্য। এটি কি আসলে একটি কনটেক্সপ্রস?


94

আমি সংকলনের সময় একটি স্ট্রিংয়ের আক্ষরিক দৈর্ঘ্য গণনা করার চেষ্টা করছি। এটি করতে আমি নিম্নলিখিত কোড ব্যবহার করছি:

#include <cstdio>

int constexpr length(const char* str)
{
    return *str ? 1 + length(str + 1) : 0;
}

int main()
{
    printf("%d %d", length("abcd"), length("abcdefgh"));
}

সবকিছু প্রত্যাশার মতো কাজ করে, প্রোগ্রামটি 4 এবং 8 মুদ্রণ করে যে ঝাঁকুনির দ্বারা উত্পন্ন সমাবেশ কোডটি দেখায় যে ফলাফলগুলি সংকলনের সময় গণনা করা হয়েছে:

0x100000f5e:  leaq   0x35(%rip), %rdi          ; "%d %d"
0x100000f65:  movl   $0x4, %esi
0x100000f6a:  movl   $0x8, %edx
0x100000f6f:  xorl   %eax, %eax
0x100000f71:  callq  0x100000f7a               ; symbol stub for: printf

আমার প্রশ্ন: এটি কি সেই মান দ্বারা গ্যারান্টিযুক্ত যে lengthফাংশনটি সংকলনের সময় মূল্যায়ন করা হবে?

যদি এটি সত্য হয় তবে সংকলন টাইম স্ট্রিং লিটারাল গণনাগুলির জন্য আমার জন্য সবেমাত্র দরজা খোলা হয়েছে ... উদাহরণস্বরূপ আমি সংকলনের সময় হ্যাশগুলি গণনা করতে পারি এবং আরও অনেক ...


4
যতক্ষণ প্যারামিটারটি একটি ধ্রুবক অভিব্যক্তি, ততক্ষণ তা অবশ্যই।
ক্রিস

4
@ ক্রিস কি এমন কোনও গ্যারান্টি আছে যে স্থির অভিব্যক্তিটির প্রয়োজন হয় না এমন প্রসঙ্গে ব্যবহৃত হলে সংকলনের সময় ধ্রুবক অভিব্যক্তি হতে পারে এমন কোনও কিছুর মূল্যায়ন করতে হবে?
টিসি

12
বিটিডাব্লু সহ, <cstdio>এবং তারপরে কল ::printfকরা অ-পোর্টেবল। মানকটি কেবল সরবরাহ <cstdio>করতে হয় std::printf
বেন ভয়েগট

4
@ বেনওয়েগ্ট ওকে, এটি দেখানোর জন্য ধন্যবাদ :) প্রথমদিকে আমি স্টাডি :: কাউট ব্যবহার করলাম, তবে উত্পন্ন কোডটি প্রকৃত মানগুলি খুঁজে পেতে বেশ বড় ছিল :)
মিরসিয়া ইস্পাস

4
@ ফিলিক্স আমি প্রায়শই গডবোল্ট ব্যবহার করি যখন অপ্টিমাইজেশনের সাথে সম্পর্কিত প্রশ্নগুলির উত্তর দেওয়া হয় এবং ব্যবহার printfকরার ফলে মোকাবেলায় উল্লেখযোগ্যভাবে কম কোড হতে পারে।
শফিক ইয়াঘমোর

উত্তর:


76

সংকলনের সময় ধ্রুবক এক্সপ্রেশন মূল্যায়নের গ্যারান্টিযুক্ত নয়, আমাদের কাছে কেবল খসড়া সি ++ স্ট্যান্ডার্ড বিভাগ থেকে একটি নন-আদর্শিক উদ্ধৃতি রয়েছে 5.19 কনস্ট্যান্ট এক্সপ্রেশন যা এটি বলে:

[...]> [দ্রষ্টব্য: অনুবাদের সময় ধ্রুবক অভিব্যক্তি মূল্যায়ন করা যায় can শেষ নোট]

constexprসংকলন সময়ে মূল্যায়ন করা হয় তা নিশ্চিত হওয়ার জন্য আপনি ফলাফলটি পরিবর্তনশীলকে নির্ধারণ করতে পারেন, আমরা এটি বার্জন স্ট্রস্ট্রপের সি ++ 11 রেফারেন্স থেকে দেখতে পারি যা বলে ( জোর আমার ):

সংকলন সময়ে এক্সপ্রেশন মূল্যায়ণ করতে সক্ষম হওয়া ছাড়াও, আমরা সংকলন সময়ে এক্সপ্রেশন মূল্যায়নের প্রয়োজন হতে সক্ষম হতে চাই ; একটি চলক সংজ্ঞার সামনে কনটেক্সপ্রস এটি করে (এবং বোঝায়):

উদাহরণ স্বরূপ:

constexpr int len1 = length("abcd") ;

বাজার্ন স্ট্রস্ট্রপ এই আইসোক্প ব্লগ এন্ট্রিতে কখন সময় মূল্যায়নের সঙ্কলনের আশ্বাস দিতে পারি তার একটি সংক্ষিপ্তসার দেয় এবং বলে:

[...] সঠিক উত্তর - হার্ব দ্বারা বর্ণিত হিসাবে - মান অনুসারে একটি কনসটেক্সার্প ফাংশনটি সংকলক সময় বা রান টাইমে মূল্যায়ন করা যেতে পারে যদি না এটি ধ্রুবক অভিব্যক্তি হিসাবে ব্যবহৃত হয়, তবে সেক্ষেত্রে এটি সংকলনের সময় মূল্যায়ন করতে হবে -কাল সংকলন-সময় মূল্যায়নের গ্যারান্টি দিতে, আমাদের হয় অবশ্যই এটি ব্যবহার করতে হবে যেখানে ধ্রুবক অভিব্যক্তি প্রয়োজন (উদাহরণস্বরূপ, একটি অ্যারে বাউন্ড হিসাবে বা কেস লেবেল হিসাবে) অথবা এটি একটি কনস্টেক্সপ্রিস সূচনা করতে ব্যবহার করতে হবে। আমি আশা করব যে কোনও স্ব-সম্মানজনক সংকলক মূলত যা বলেছিলাম তা করার অপ্টিমাইজেশনের সুযোগটি হাতছাড়া করবে না: "যদি সমস্ত যুক্তি ধ্রুবক প্রকাশ হয় তবে একটি কনটেক্সপ ফাংশন সংকলন সময়ে মূল্যায়ন করা হয়।"

সুতরাং এটি দুটি ক্ষেত্রে রূপরেখা দেয় যেখানে সংকলনের সময় এটি মূল্যায়ন করা উচিত:

  1. যেখানে ধ্রুবক অভিব্যক্তি প্রয়োজন সেখানে এটি ব্যবহার করুন, এটি খসড়া স্ট্যান্ডার্ডের যেখানে বাক্যাংশ shall be ... converted constant expressionবা anywhereshall be ... constant expression ব্যবহৃত হয়েছে যেমন অ্যারে বাউন্ড হিসাবে মনে হবে।
  2. এটি আরম্ভ করার জন্য ব্যবহার করুন constexprআমি উপরের রূপরেখার হিসাবে ।

4
এটি বলেছে যে, নীতিগতভাবে একটি সংকলক অভ্যন্তরীণ বা কোনও সংযোগের সাথে কোনও বস্তু দেখার জন্য অধিকারী constexpr int x = 5;, লক্ষ্য করুন যে এটি সংকলন-সময়ে মূল্য প্রয়োজন হয় না (ধরে নিলে এটি কোনও টেম্পলেট প্যারামিটার বা হোয়াট নোট হিসাবে ব্যবহৃত হয় না) এবং প্রকৃতই নির্গত হয় কোড যা রানটাইমে প্রাথমিক মানটি 1 এবং 4 সংযোজন অপের 5 তাত্ক্ষণিক মানগুলি ব্যবহার করে। আরও বাস্তব উদাহরণ: সংকলকটি একটি পুনরাবৃত্তি সীমাতে আঘাত করতে পারে এবং রানটাইম পর্যন্ত গণনা পিছিয়ে দিতে পারে। আপনি যদি এমন কিছু না করেন যা সংকলককে প্রকৃতপক্ষে মানটি ব্যবহার করতে বাধ্য করে, "সংকলন সময়ে মূল্যায়নের গ্যারান্টিযুক্ত" একটি QOI সমস্যা।
স্টিভ জেসোপ

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

4
আমি মনে করি যে তারা উভয়ই "স্ব-সম্মানমূলক সংকলক" বিবেচনা করছে, মান-সম্মত হওয়ার বিপরীতে তবে ইচ্ছাকৃতভাবে বাধা সংকলক আমি অনুমান করি। এটা সম্পর্কে কি মান আসলে যুক্তি একটি উপায় হিসেবে উপযোগী গ্যারান্টী , এবং আরো অনেক অন্য না ;-)
স্টিভ জেসপ

4
@ স্টেজেজাপ কুখ্যাত (এবং দুর্ভাগ্যবশত অস্তিত্বহীন) হেল ++ এর মতো ইচ্ছাকৃতভাবে প্রতিবন্ধক সংকলকগণ সংজ্ঞা / বহনযোগ্যতার পরীক্ষার জন্য এ জাতীয় জিনিসটি দুর্দান্ত great
অ্যাঞ্জিউ আর

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

27

কোনও constexprক্রিয়াকলাপের কলটি কোনও স্থির অভিব্যক্তির ফলাফল দেয় বা নিখুঁতভাবে অনুকূলিত হচ্ছে কিনা তা খুঁজে পাওয়া সত্যিই সহজ :

এটিকে এমন প্রসঙ্গে ব্যবহার করুন যেখানে ধ্রুবক অভিব্যক্তি প্রয়োজন।

int main()
{
    constexpr int test_const = length("abcd");
    std::array<char,length("abcdefgh")> test_const2;
}

4
... এবং -pedanticআপনি জিসিসি ব্যবহার করে সংকলন করুন । অন্যথায়, আপনি কোনও সতর্কতা এবং ত্রুটিগুলি পাবেন না
BЈовић

@ বিЈовић বা এটি এমন একটি প্রসঙ্গে ব্যবহার করুন যেখানে জিসিসির সম্ভাব্য কোনও উপায় যেমন কোনও টেমপ্লেট আর্গুমেন্ট পাচ্ছে না।
এঞ্জিউ আর

Wouldn \ T একটি enum হ্যাক অধিক নির্ভরযোগ্য হতে পারে? যেমন enum { Whatever = length("str") }?
ধারালো টুথ

18
উল্লেখ যোগ্যstatic_assert(length("str") == 3, "");
ক্রিস

8
constexpr auto test = /*...*/;সম্ভবত সবচেয়ে সাধারণ এবং সোজা।
টিসি

19

কেবল একটি নোট, যে আধুনিক সংকলকগণ (যেমন gcc-4.x) strlenসংকলনের সময় স্ট্রিং লিটারেলের জন্য করেন কারণ এটি সাধারণত অভ্যন্তরীণ ফাংশন হিসাবে সংজ্ঞায়িত করা হয় । কোনও অপ্টিমাইজেশন সক্ষম করা নেই। যদিও ফলাফলটি একটি সংকলন সময় ধ্রুবক নয়।

যেমন:

printf("%zu\n", strlen("abc"));

ফলাফল স্বরূপ:

movl    $3, %esi    # strlen("abc")
movl    $.LC0, %edi # "%zu\n"
movl    $0, %eax
call    printf

দ্রষ্টব্য, এটি কাজ করে কারণ strlenএটি একটি অন্তর্নির্মিত ফাংশন, যদি আমরা -fno-builtinsএটি রান-টাইমে কল করার জন্য ফিরে আসে তবে এটি সরাসরি দেখুন
শফিক ইয়াঘমুর

strlenহয় constexprএমনকি আমার জন্যে, -fno-nonansi-builtins(মত মনে হয় -fno-builtins++, কোন গ্রাম বিদ্যমান নেই)। আমি "কনটেক্সটপ্রিপ" বলছি, কারণ আমি এটি করতে পারি template<int> void foo();এবং foo<strlen("hi")>(); জি ++ - 4.8.4
অ্যারন

19

আমি আর একটি ফাংশন প্রস্তাব করি যা সংকলন সময়ে স্ট্রিংয়ের দৈর্ঘ্যকে পুনরাবৃত্তি না করে গণনা করে।

template< size_t N >
constexpr size_t length( char const (&)[N] )
{
  return N-1;
}

আইডিয়োনে এই নমুনা কোডটি দেখুন ।


4
এম্বেড থাকা '\ 0' এর কারণে এটি স্ট্রেনের সমান হতে পারে না: স্ট্রেলেন ("হাই \ 0the")! = দৈর্ঘ্য ("হাই \ 0 এখানে")
আনকুলঙ্কুলু

এটি সঠিক উপায়, এটি কার্যকর আধুনিক সি ++ এর একটি উদাহরণ (যদি আমি সঠিকভাবে মনে করি)। তবে, একটি দুর্দান্ত স্ট্রিং ক্লাস রয়েছে যা সম্পূর্ণরূপে এই উত্তরটি দেখছে না: স্কট শুরার আর্ট_কনস্ট , সম্ভবত এটি আরও কার্যকর হবে (এবং কম সি স্টাইল)।
কোয়ান্টাম কার্ল

@ মাইকওয়ের অপ্স, এটি অদ্ভুত। এখানে বিভিন্ন লিঙ্ক প্রশ্নের লিংক , কাগজ লিংক , Git উপর উৎসে লিংক
QuantumKarl

এখন char temp[256]; sprintf(temp, "%u", 2); if(1 != length(temp)) printf("Your solution doesn't work"); ইয়ে
পাবলো অ্যারিয়েল

7

constexprসংকলন-সময়ে কোনও ফাংশনটি মূল্যায়ন করার কোনও গ্যারান্টি নেই , যদিও কোনও যুক্তিসঙ্গত সংকলক এটি উপযুক্ত অপ্টিমাইজেশন স্তরে সক্ষম করবে। অন্যদিকে, সংকলন সময়ে টেমপ্লেটের প্যারামিটারগুলি মূল্যায়ন করতে হবে।

সংকলনের সময় মূল্যায়নের জন্য জোর করতে আমি নিম্নলিখিত কৌশলটি ব্যবহার করেছি। দুর্ভাগ্যক্রমে এটি কেবল অবিচ্ছেদ্য মানগুলির সাথে কাজ করে (যেমন ভাসমান পয়েন্টের মানগুলির সাথে নয়)।

template<typename T, T V>
struct static_eval
{
  static constexpr T value = V;
};

এখন, আপনি যদি লিখুন

if (static_eval<int, length("hello, world")>::value > 7) { ... }

আপনি নিশ্চিত হতে পারেন যে ifবিবৃতিটি একটি রান-টাইম ওভারহেড ছাড়াই একটি সংকলন-ধ্রুবক।


8
অথবা কেবল স্ট্যান্ড :: ইন্টিগ্রাল_
কনস্ট্যান্ট

4
উদাহরণটি অর্থহীন ব্যবহারের কিছু কারণ যেহেতু সংকলন সময়ে যেভাবেই lenহওয়া উচিত constexprমানে lengthহওয়া উচিত।
ক্রিস

@chris আমি এটা জানতাম না উচিত নয় হতে যদিও আমি পালন করেছেন আইটি হয় আমার কম্পাইলার সঙ্গে।
5gon12eder

ঠিক আছে, সংখ্যাগরিষ্ঠ অন্যান্য উত্তর অনুসারে এটির রয়েছে, তাই আমি উদাহরণটিকে কম অর্থহীন হতে সংশোধন করেছি। প্রকৃতপক্ষে, এটি একটি ifশর্ত ছিল (যেখানে এটি কম্পাইলারটি ডেড কোড নির্মূল করায় প্রয়োজনীয় ছিল) যার জন্য আমি মূলত কৌশলটি ব্যবহার করেছি used
5gon12eder

1

সাধারণ ধ্রুবক মত প্রকাশের উপর উইকিপিডিয়ায় প্রবেশের একটি সংক্ষিপ্ত ব্যাখ্যা :

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

কোনও constexprফাংশন সংজ্ঞার আগে কীওয়ার্ড থাকা সংকলককে এই সীমাবদ্ধতাগুলি পূরণ করা হয়েছে কিনা তা পরীক্ষা করার নির্দেশ দেয়। যদি হ্যাঁ, এবং ফাংশনটি একটি ধ্রুবক সহ কল ​​করা হয়, প্রত্যাবর্তিত মানটি ধ্রুবক হওয়ার গ্যারান্টিযুক্ত এবং সুতরাং যে কোনও স্থানে ধ্রুবক অভিব্যক্তি প্রয়োজন হয় ব্যবহার করা যেতে পারে।


এই শর্তগুলি প্রত্যাশিত মান ধ্রুবক গ্যারান্টি দেয় না । উদাহরণস্বরূপ, ফাংশনটি অন্যান্য আর্গুমেন্ট মানগুলির সাথে ডাকা হতে পারে।
বেন ভয়েগ্ট

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