"স্থির" বা "বাহ্যিক" ছাড়াই "ইনলাইন" কি সি 99 এ কখনও কার্যকর?


98

যখন আমি এই কোডটি তৈরি করার চেষ্টা করি

inline void f() {}

int main()
{
    f();
}

কমান্ড লাইন ব্যবহার করে

gcc -std=c99 -o a a.c

আমি একটি লিঙ্কারের ত্রুটি পেয়েছি (এ সম্পর্কে অনির্ধারিত উল্লেখ f) আমি যদি ব্যবহার করি static inlineবা ন্যায়বিচারের extern inlineপরিবর্তে inlineবা আমি সংকলন করি তবে ত্রুটিটি অদৃশ্য হয়ে যায় -O(যাতে ফাংশনটি আসলে ইনলাইনড থাকে)।

এই আচরণটি C99 স্ট্যান্ডার্ডের 6.7.4 (6) অনুচ্ছেদে সংজ্ঞায়িত করা বলে মনে হচ্ছে:

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

আমি যদি এগুলি সঠিকভাবে বুঝতে পারি inlineতবে উপরের উদাহরণ হিসাবে বর্ণিত একটি ফাংশন সহ একটি সংকলন ইউনিট কেবল একই নামের সাথে একটি বাহ্যিক ফাংশন উপস্থিত থাকলে কেবল ধারাবাহিকভাবে কম্পাইল করে এবং আমার নিজের ফাংশন বা বাহ্যিক ফাংশন বলা হয় কিনা তা আমি কখনই জানতে পারি না।

এই আচরণ কি পুরোপুরি বোকা নয়? C99 inlineছাড়াই staticবা কোনও ফাংশন সংজ্ঞায়িত করা কি কখনও কার্যকর extern? আমি কিছু অনুপস্থিত করছি?

উত্তরের সংক্ষিপ্তসার

অবশ্যই আমি কিছু অনুপস্থিত ছিল, এবং আচরণটি মূর্খ নয়। :)

নিমো যেমন ব্যাখ্যা করেছেন তেমন ধারণাটি হ'ল ফাংশনের সংজ্ঞা দেওয়া উচিত

inline void f() {}

শিরোনাম ফাইল এবং শুধুমাত্র একটি ঘোষণা

extern inline void f();

সংশ্লিষ্ট .c ফাইলে। কেবলমাত্র externঘোষণাটি বাহ্যিকভাবে দৃশ্যমান বাইনারি কোডের প্রজন্মকে ট্রিগার করে। এবং প্রকৃতপক্ষে inline.c ফাইলে কোনও ব্যবহার নেই - এটি কেবল শিরোনামগুলিতেই কার্যকর।

হিসাবে C99 কমিটি যোনাথনের উত্তর উদ্ধৃত এর যুক্তিপূর্ণ explicates, inlineকম্পাইলার optimisations যে একটা ফাংশন সংজ্ঞার প্রয়োজন একটি কলের সাইট এ দৃশ্যমান হতে সম্পর্কে। এটি কেবল শিরোনামটিতে সংজ্ঞা রেখেই অর্জন করা যায় এবং অবশ্যই একটি শিরোনামে একটি সংজ্ঞা সংকলক দ্বারা প্রতিবারই দেখা যায় না তাই কোড নির্গত হয় না। কিন্তু যেহেতু সংকলক আসলে কোনও ফাংশনটি ইনলাইন করতে বাধ্য হয় না, তাই বাহ্যিক সংজ্ঞাটি কোথাও উপস্থিত থাকতে হবে।


সীমান্তরেখা এর সদৃশ stackoverflow.com/questions/5369888/...
Earlz


@ এয়ারলজ: লিঙ্কটির জন্য ধন্যবাদ। আমার প্রশ্নটি স্ট্যান্ডার্ডের উদ্ধৃত অনুচ্ছেদের পিছনে যৌক্তিকতা সম্পর্কে এবং যদি কখনও inlineনা থাকে staticএবং externযদিও এর জন্য কেস ব্যবহার করা হয় । দুর্ভাগ্যক্রমে, এই বিষয়গুলির কোনওটিই সেই প্রশ্নের আওতায় আসে না।
সোভেন মারনাচ

@ নিমো: আমি আমার পোস্ট করার আগে এই প্রশ্নটি এবং উত্তরগুলি পড়েছিলাম। আবার, আমি জিজ্ঞাসা করছি না "এটি কেমন আচরণ করে?" তবে বরং "এই আচরণের পিছনে কী ধারণা রয়েছে"? আমি নিশ্চিত আমি এখানে কিছু মিস করছি।
সোভেন মারনাচ

4
হ্যাঁ, এজন্যই আমি "সীমান্তরেখা" বলেছিলাম। আমি ব্যক্তিগতভাবে মনে করি এটি সম্পূর্ণ আলাদা প্রশ্ন জিজ্ঞাসা করছে
আর্লজ

উত্তর:


40

আসলে এই দুর্দান্ত উত্তরটি আপনার প্রশ্নেরও উত্তর দেয়, আমার ধারণা:

বহির্মুখী ইনলাইন কী করে?

ধারণাটি হ'ল "ইনলাইন" একটি শিরোলেখ ফাইলটিতে এবং তারপরে একটি .c ফাইলে "বহিরাগত ইনলাইন" ব্যবহার করা যেতে পারে। "এক্সটার্নাল ইনলাইন" ঠিক কীভাবে আপনি কম্পাইলারকে নির্দেশ দিন যে কোন ফাইল ফাইলটিতে (বাহ্যিকভাবে দৃশ্যমান) উত্পন্ন কোড থাকা উচিত।

[আপডেট করার জন্য, বিস্তারিত জানাতে]

আমি মনে করি না .c ফাইলে "ইনলাইন" ("স্ট্যাটিক" বা "বাহ্যিক" ছাড়াই) কোনও ব্যবহার আছে। তবে একটি শিরোনাম ফাইলে এটি উপলব্ধি করে এবং প্রকৃতপক্ষে একক কোড তৈরি করতে কিছু .c ফাইলে এটি সম্পর্কিত "বাহ্যিক ইনলাইন" ঘোষণার প্রয়োজন হয়।


4
ধন্যবাদ, আমি ধারণা পেতে শুরু করছি!
সোভেন মারনাচ

8
হ্যাঁ, আমি এখন পর্যন্ত এটিকে কখনও বুঝতে পারি নি, তাই জিজ্ঞাসার জন্য ধন্যবাদ :-)। এটি অদ্ভুত যে নন-এক্সটার্নাল "ইনলাইন" সংজ্ঞাটি শিরোনামে যায় (তবে অগত্যা কোনও কোড উত্পন্ন করতে পারে না), যখন "বহির্মুখী ইনলাইন" ঘোষণাপত্র .c ফাইলে যায় এবং আসলে কোডটি সৃষ্টি করে উত্পন্ন করা।
নিমো

4
এর অর্থ কি আমি inline void f() {}হেডার এবং extern inline void f();.c ফাইলে লিখি ? সুতরাং আসল ফাংশন সংজ্ঞা শিরোনামে যায় এবং .c ফাইলের ক্ষেত্রে এই ক্ষেত্রে একটি সাধারণ ঘোষণার বিপরীতে কোনও ক্রম থাকে?
সোভেন মারনাচ

4
@ এন্ডোলিথ: আপনার প্রশ্নটি আমি বুঝতে পারি না। আমরা inline ছাড়া static বা আলোচনা করছি extern। অবশ্যই static inlineঠিক আছে, তবে এই প্রশ্ন এবং উত্তর সম্পর্কে যা তা নয়।
নিমো

4
@ ম্যাথিউইউময় এর -std=c99পরিবর্তে আপনার ব্যবহারের প্রয়োজন -std=gnu89
a3f

27

মানক (আইএসও / আইইসি 9899: 1999) থেকে নিজেই:

পরিশিষ্ট J.2 অপরিবর্তিত আচরণ

  • ...
  • বাহ্যিক সংযোগ সহ একটি ফাংশনটি একটি দ্বারা ঘোষণা করা হয় inline ফাংশন ফাংশন সুনির্দিষ্ট , তবে একই অনুবাদ ইউনিটে (6.7.4) এও সংজ্ঞায়িত হয় না।
  • ...

সি 99 কমিটি একটি যুক্তি লিখেছিল এবং তাতে বলা হয়েছে:

6.7.4 ফাংশন নির্দিষ্টকারী

C99 এর একটি নতুন বৈশিষ্ট্য:inline শব্দ, সি থেকে অভিযোজিত ++ একটি হল ফাংশন-সুনির্দিষ্টভাবে উল্লেখ করা যে শুধুমাত্র ফাংশন ঘোষণা ব্যবহার করা যেতে পারে। এটি প্রোগ্রামের অপ্টিমাইজেশনের জন্য দরকারী যা কোনও ফাংশনের সংজ্ঞাটি কোনও কলটির সাইটে দৃশ্যমান হওয়া প্রয়োজন। (নোট করুন যে স্ট্যান্ডার্ড এই অপ্টিমাইজেশনের প্রকৃতি নির্দিষ্ট করার চেষ্টা করে না))

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

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

একটি প্রোগ্রামে একটি বাহ্যিক সংজ্ঞা সহ একটি অনুবাদ ইউনিট, একটি ইনলাইন সংজ্ঞা সহ একটি অনুবাদ ইউনিট, এবং একটি ঘোষণার সাথে একটি অনুবাদ ইউনিট থাকতে পারে তবে কোনও কার্যের জন্য কোনও সংজ্ঞা থাকতে পারে। পরবর্তী অনুবাদ ইউনিটে কলগুলি যথারীতি বাহ্যিক সংজ্ঞা ব্যবহার করবে।

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

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

inline const char *saddr(void)
{
    static const char name[] = "saddr";
    return name;
}
int compare_name(void)
{
    return saddr() == saddr(); // unspecified behavior
}

যেহেতু বাস্তবায়ন কোনও কলের জন্য ইনলাইন সংজ্ঞাটি ব্যবহার করতে পারে saddrএবং অন্যটির জন্য বাহ্যিক সংজ্ঞা ব্যবহার করতে পারে তাই সমতা অপারেশনটি 1 (সত্য) এর মূল্যায়ন করার গ্যারান্টিযুক্ত নয়। এটি দেখায় যে ইনলাইন সংজ্ঞার মধ্যে সংজ্ঞায়িত স্থিতিক বস্তুগুলি বাহ্যিক সংজ্ঞায় তাদের সংশ্লিষ্ট বস্তু থেকে পৃথক। এটি এমনকি একটি অ-const এই ধরণের অবজেক্টকে ।

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

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

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

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

#define abs(x) __builtin_abs(x)

অথবা স্ট্যান্ডার্ড লাইব্রেরি ফাংশনগুলি ইনলাইন করার জন্য অন্যান্য অ-বহনযোগ্য ব্যবস্থা।


ধন্যবাদ, এটি খুব বিস্তারিত - এবং স্ট্যান্ডার্ডের মতোই পাঠযোগ্য। :-) আমি জানতাম আমি অবশ্যই কিছু মিস করছি। আপনি কোথা থেকে একটি রেফারেন্স দিতে পারেন?
সোভেন মারনাচ

: এটা শুধু আমার মন যে আপনি যদি লিঙ্ক খোঁজার জন্য Google ব্যবহার করতে পারেন অতিক্রম open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf
সেভেন Marnach

@ সোভেন: আমি আপনার অনুসন্ধান থেকে ইউআরএল ধার করেছি এবং এটি উত্তরে রেখেছি আমি যে দস্তাবেজটি ব্যবহার করেছি সেটি হ'ল আমি পূর্বে সংরক্ষণ করা যুক্তিগুলির অনুলিপি (2005 সালে), তবে এটি V5.10ও ছিল।
জোনাথন লেফলার

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

0

> আমি একটি লিঙ্কারের ত্রুটি পেয়েছি (এর জন্য অপরিবর্তিত রেফারেন্স f)

এখানে কাজ করে: লিনাক্স x86-64, জিসিসি 4.1.2। আপনার সংকলকটিতে একটি বাগ হতে পারে; প্রদত্ত প্রোগ্রামটিকে নিষিদ্ধ করা মান থেকে উদ্ধৃত অনুচ্ছেদে আমি কিছুই দেখতে পাচ্ছি না। Iff এর চেয়ে if এর ব্যবহারটি নোট করুন ।

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

সুতরাং, যদি আপনি ফাংশনটির আচরণটি জানেন fএবং আপনি এটিকে একটি শক্ত লুপে কল করতে চান, তবে ফাংশন কলগুলি প্রতিরোধ করার জন্য আপনি একটি সংকলনটিতে এর সংজ্ঞাটি অনুলিপি করতে পারেন; বা , আপনি একটি সংজ্ঞা প্রদান করতে পারেন যা বর্তমান মডিউলটির উদ্দেশ্যে, সমতুল্য (তবে ইনপুট বৈধতা বা আপনি যে কোনও অপ্টিমাইজেশন কল্পনা করতে পারেন) এড়িয়ে যায়। সংকলক লেখকের কাছে তবে পরিবর্তে প্রোগ্রাম আকারের জন্য অনুকূলিতকরণের বিকল্প রয়েছে।


4
স্ট্যান্ডার্ডটি বলে যে সংকলকটি সর্বদা ধরে নিতে পারে যে একই নামের সাথে একটি বহিরাগত ফাংশন রয়েছে এবং ইনলাইন সংস্করণের পরিবর্তে এটি কল করতে পারে, তাই আমি মনে করি না এটি একটি সংকলক বাগ। আমি জিসিসি ৪.৩, ৪.৪ এবং ৪.৪ দিয়ে চেষ্টা করেছি, সবাই লিঙ্কারের ত্রুটি দেয়।
সোভেন মারনাচ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.