সি এবং সি ++ এর মধ্যে 'কনস্ট্যান্ট স্ট্যাটিক' অর্থ কী?


117
const static int foo = 42;

আমি স্ট্যাকওভারফ্লোতে এখানে কিছু কোডে দেখেছি এবং এটি কী করে তা বুঝতে পারি না। তারপরে আমি অন্যান্য ফোরামে কিছু বিভ্রান্ত উত্তর দেখেছি। আমার সেরা অনুমান যে এটি fooঅন্য মডিউল থেকে ধ্রুবকটি আড়াল করতে সি তে ব্যবহৃত হয় । এটা কি সঠিক? যদি তা হয় তবে কেন কেউ কেন এটি সি ++ এর প্রসঙ্গে ব্যবহার করতে পারবেন যেখানে আপনি কেবল এটি তৈরি করতে পারেন private?

উত্তর:


113

এটি সি এবং সি ++ উভয়ই ব্যবহার করে।

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

সি এই ভেরিয়েবলগুলির সাথে কীভাবে আচরণ করে (বা সি ++ নামস্থান ভেরিয়েবলগুলি কীভাবে আচরণ করে)। সি ++ এ চিহ্নিত চিহ্নিত সদস্যকে staticপ্রদত্ত শ্রেণীর সমস্ত দৃষ্টান্ত ভাগ করে নেওয়া হয়। এটি ব্যক্তিগত হোক বা না এই বিষয়টি প্রভাবিত করে না যে একটি ভেরিয়েবল একাধিক উদাহরণ দ্বারা ভাগ করা হয়েছে। রয়ে constসেখানে আপনাকে সতর্ক যদি থাকে কোডটি পরিবর্তন করার চেষ্টা করবে হবে।

যদি এটি কঠোরভাবে ব্যক্তিগত ছিল, তবে শ্রেণীর প্রতিটি উদাহরণ তার নিজস্ব সংস্করণ (অপটিমাইজার সত্ত্বেও) পাবে।


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

"বিশেষ বিভাগ" ডেটা বিভাগ হিসাবে পরিচিত, যা এটি অন্যান্য গ্লোবাল ভেরিয়েবলগুলির সাথে সুস্পষ্ট "স্ট্রিংস" এবং গ্লোবাল অ্যারেগুলির সাথে ভাগ করে। এটি কোড বিভাগের বিরোধিতা করছে।
স্পোলসন 10

@ রিচার্ড - আপনি কি মনে করেন এটি কোনও শ্রেণীর সদস্য? প্রশ্নটিতে এমন কিছুই নেই যা বলে যে এটি। যদি এটি কোনও শ্রেণীর সদস্য হয়, তবে আপনি ঠিক বলেছেন, তবে এটি যদি বিশ্বব্যাপী স্কোপ হিসাবে ঘোষিত একটি পরিবর্তনশীল হয় তবে ক্রিস সঠিক।
গ্রামীণ পেরো

1
মূল পোস্টারটি সম্ভাব্য উন্নত সমাধান হিসাবে ব্যক্তিগত হিসাবে উল্লেখ করেছে, তবে মূল সমস্যা হিসাবে নয়।
ক্রিস আরগুইন

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

212

প্রচুর লোকেরা মৌলিক উত্তর দেয় কিন্তু কেউই চিহ্নিত করেনি যে সি ++ তে স্তরে constডিফল্ট রয়েছে (এবং কেউ কেউ ভুল তথ্য দিয়েছেন)। সি ++ 98 স্ট্যান্ডার্ড বিভাগটি 3.5.3 দেখুন।staticnamespace

প্রথম কিছু পটভূমি:

অনুবাদ ইউনিট: প্রাক-প্রসেসরের পরে একটি উত্স ফাইল (পুনরাবৃত্তভাবে) এর সমস্ত ফাইল অন্তর্ভুক্ত করে।

স্থিতিশীল লিঙ্কেজ: একটি অনুবাদ কেবল তার অনুবাদ ইউনিটের মধ্যেই উপলব্ধ।

বাহ্যিক সংযোগ: অন্য অনুবাদ ইউনিট থেকে একটি প্রতীক পাওয়া যায়।

namespaceস্তর

এর মধ্যে রয়েছে বিশ্বব্যাপী নেমস্পেস ওরফে গ্লোবাল ভেরিয়েবল

static const int sci = 0; // sci is explicitly static
const int ci = 1;         // ci is implicitly static
extern const int eci = 2; // eci is explicitly extern
extern int ei = 3;        // ei is explicitly extern
int i = 4;                // i is implicitly extern
static int si = 5;        // si is explicitly static

ফাংশন পর্যায়ে

staticমানে ফাংশন কলগুলির মধ্যে মান বজায় থাকে।
ফাংশন staticভেরিয়েবলের শব্দার্থকতা বৈশ্বিক ভেরিয়েবলের সমান যে তারা প্রোগ্রামের ডেটা-সেগমেন্টে থাকে (এবং স্ট্যাক বা হিপ নয়), ভেরিয়েবলের আজীবন সম্পর্কে আরও বিশদে এই প্রশ্নটি দেখুন static

classস্তর

staticমানে মানটি শ্রেণীর সমস্ত দৃষ্টান্তের মধ্যে ভাগ করা হয় এবং এর constঅর্থ এটি পরিবর্তন হয় না।


2
ফাংশন স্তরে: স্ট্যাটিক const সঙ্গে reduntant করা হয় না, তারা ভিন্নভাবে আচরণ করতে const int *foo(int x) {const int b=x;return &b};বনামconst int *foo(int x) {static const int b=x;return &b};
Hanczar

1
প্রশ্নটি সি এবং সি ++ উভয়ের ক্ষেত্রেই তাই আপনার constকেবলমাত্র staticপরবর্তী ক্ষেত্রে অন্তর্ভুক্ত সম্পর্কে একটি নোট অন্তর্ভুক্ত করা উচিত ।
নিকোলাই রুহে

@ মোটি: দুর্দান্ত উত্তর। আপনি কি দয়া করে ব্যাখ্যা করতে পারেন কোন ফাংশন স্তরের ফলে কি বাজে? আপনি কি বলছেন যে constঘোষণার বিষয়টি staticসেখানেও বোঝায় ? যেমনটি, আপনি যদি ফেলে constদেন, এবং মানটি সংশোধন করেন, সমস্ত মান সংশোধিত হবে?
কুকি

1
@ মট্টি constফাংশন স্তরে স্থির বোঝায় না, এটি এক সার্থক দুঃস্বপ্ন (কনস্ট! = ধ্রুবক অভিব্যক্তি) হবে, ফাংশন স্তরের সমস্ত কিছুই স্পষ্টতই auto। যেহেতু এই প্রশ্নটিকেও ট্যাগ করা হয়েছে, আমারও উল্লেখ করা উচিত যে বিশ্বব্যাপী স্তরটি const intস্পষ্টভাবে externসি তে রয়েছে তবে আপনি এখানে যে বিধিগুলি দিয়েছেন সেগুলি পুরোপুরি সি ++ এর বর্ণনা দেয়।
রায়ান হেইনিং

1
এবং সি ++ এ তিনটি ক্ষেত্রেই staticইঙ্গিত দেয় যে চলকটি স্থির সময়সীমার (শুধুমাত্র একটি অনুলিপি উপস্থিত থাকে যা প্রোগ্রামের শুরু থেকে শেষ অবধি স্থায়ী হয়), এবং অভ্যন্তরীণ / স্থিতিশীল যোগসূত্র থাকে অন্যথায় নির্দিষ্ট না হলে (এটি ফাংশনটির দ্বারা ওভাররাইড করা হয়) স্থানীয় স্ট্যাটিক ভেরিয়েবলের জন্য লিঙ্কেজ, বা ক্লাসের 'স্ট্যাটিক সদস্যদের লিঙ্কেজ)। মূল পার্থক্যগুলি staticহ'ল বৈধ যেখানে প্রতিটি পরিস্থিতিতে এটি বোঝায় ।
জাস্টিন সময় - মনিকা 22

45

কোডটির সেই লাইনটি বেশ কয়েকটি বিভিন্ন প্রসঙ্গে উপস্থিত হতে পারে এবং এটি প্রায় একই রকম আচরণ করে, ছোট পার্থক্য রয়েছে।

নাম স্পেস

// foo.h
static const int i = 0;

' i' শিরোনাম সহ প্রতিটি অনুবাদ ইউনিটে দৃশ্যমান হবে। যাইহোক, যদি না আপনি আসলে বস্তুর ঠিকানা ব্যবহার (উদাহরণস্বরূপ। ' &i'), আমি নিশ্চিত যে কম্পাইলার বিবেচনা করবে আছি ' iকেবল একটি টাইপ নিরাপদ হিসাবে' 0। যেখানে আরও দুটি অনুবাদ ইউনিট ' &i' নেয় তখন প্রতিটি অনুবাদ ইউনিটের ঠিকানাটি আলাদা হবে।

// foo.cc
static const int i = 0;

' i' এর অভ্যন্তরীণ সংযোগ রয়েছে, এবং তাই এই অনুবাদ ইউনিটের বাইরে থেকে উল্লেখ করা যায় না। তবে, আপনি যদি আবার এর ঠিকানা ব্যবহার না করেন তবে সম্ভবত এটি টাইপ-সেফ হিসাবে বিবেচিত হবে 0

একটি বিষয় উল্লেখযোগ্য যে, নিম্নলিখিত ঘোষণাটি হ'ল:

const int i1 = 0;

হয় ঠিক হিসাবে একই static const int i = 0। নামের সাথে constস্পষ্টভাবে ঘোষিত না করে এবং ঘোষিত নয় এমন একটি স্থানের পরিবর্তনশীল স্পষ্টতই externস্থির। আপনি যদি এটি নিয়ে ভাবেন তবে সিডি ++ কমিটির উদ্দেশ্য ছিল ওডিআর না ভাঙতে constসর্বদা staticকীওয়ার্ডের প্রয়োজন ছাড়াই শিরোনাম ফাইলগুলিতে ভেরিয়েবলগুলি ঘোষণার অনুমতি দেওয়া ।

ক্লাস স্কোপ

class A {
public:
  static const int i = 0;
};

উপরের উদাহরণে, স্ট্যান্ডার্ড স্পষ্টভাবে নির্দিষ্ট করে যে ' i' এর সংজ্ঞা দেওয়ার প্রয়োজন নেই যদি এর ঠিকানা প্রয়োজন হয় না। অন্য কথায় আপনি যদি কেবল ' i' টাইপ-নিরাপদ 0 হিসাবে ব্যবহার করেন তবে সংকলক এটি সংজ্ঞায়িত করবে না। শ্রেণি এবং নেমস্পেস সংস্করণগুলির মধ্যে একটি পার্থক্য হ'ল ' i' এর ঠিকানা (যদি আরও দুটি আকরিক অনুবাদ ইউনিটে ব্যবহৃত হয়) শ্রেণীর সদস্যের জন্য একই হবে। যেখানে ঠিকানা ব্যবহার করা হয়েছে, আপনার অবশ্যই এটির একটি সংজ্ঞা থাকতে হবে:

// a.h
class A {
public:
  static const int i = 0;
};

// a.cc
#include "a.h"
const int A::i;            // Definition so that we can take the address

2
+1 দেখানোর জন্য যে স্ট্যাটিক কনস্ট কেবল নেমস্পেসের স্কোপের মতোই কনস্ট।
প্লুমেন্টেটর

"Foo.h" বা "foo.cc" এ স্থাপনের মধ্যে আসলে কোনও পার্থক্য নেই কারণ অনুবাদ ইউনিটটি সংকলন করার সময় .H কেবল অন্তর্ভুক্ত থাকে।
মিখাইল

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

24

এটি একটি ছোট স্থান অপ্টিমাইজেশন।

যখন তুমি বললে

const int foo = 42;

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

extern const int foo;

এর মান অ্যাক্সেস পেতে। এটি একটি ভাল অনুশীলন নয় যেহেতু সেই সংকলন ইউনিটের ফু এর মান কী তা কোনও ধারণা নেই। এটি কেবল এটি জানে যে এটি একটি অন্তঃসত্ত্বা এবং যখনই এটি ব্যবহৃত হয় তখন মেমরি থেকে মানটি পুনরায় লোড করতে হয়।

এখন এটি স্থির ঘোষণা করে:

static const int foo = 42;

সংকলকটি তার যথাযথ অপ্টিমাইজেশন করতে পারে তবে এটিও বলতে পারে "আরে, এই সংকলনের ইউনিটের বাইরে কেউ ফুও দেখতে পাবে না এবং আমি জানি এটি সর্বদা ৪২ সুতরাং এর জন্য কোনও স্থান বরাদ্দ করার দরকার নেই।"

আমার আরও নোট করা উচিত যে সি ++ এ, বর্তমান সংকলন ইউনিট থেকে নামগুলি রোধ করতে পছন্দসই উপায় হ'ল একটি অনামী নেমস্পেস ব্যবহার করা:

namespace {
    const int foo = 42; // same as static definition above
}

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

@ এন.নিহার - স্ট্যাটিক ডেটা অঞ্চলটি মেমরির একটি স্থির আকারের অংশ যাতে স্ট্যাটিক লিঙ্কেজ থাকা সমস্ত ডেটা থাকে। প্রোগ্রামটি মেমোরিতে লোড করার প্রক্রিয়া দ্বারা এটি "বরাদ্দ"। এটি স্ট্যাক বা স্তূপের অংশ নয়।
ফের্রুসিও 10

আমার যদি কোনও ফাংশন থাকে তবে ফুতে কোনও পয়েন্টার ফেরত দেয়? এটি কি অপ্টিমাইজেশনকে ভঙ্গ করে?
এনডাব্লু

@ এনডব্লিউ: হ্যাঁ, এটি করতে হবে।
ফেরুঁচিও

8

এটি একটি 'অন্তর্গত' অনুপস্থিত। এটা করা উচিত:

const static int foo = 42;

সি এবং সি ++ এ এটি স্থানীয় মানের 42 নম্বর মানের সাথে একটি পূর্ণসংখ্যার ধ্রুবক ঘোষণা করে।

কেন 42? আপনি যদি ইতিমধ্যে জানেন না (এবং আপনি বিশ্বাস করেননি এটি কঠিন), এটি জীবনের উত্তর, মহাবিশ্ব এবং সমস্ত কিছুর একটি উল্লেখ ।


ধন্যবাদ ... এখনি সর্বদা ... আমার সারা জীবনের জন্য ... যখন আমি 42 দেখি, আমি সবসময় এই বিষয়ে কিছু করব। হা হা
ইনিশির

এটি প্রমাণ-পজিটিভ যে মহাবিশ্বটি 13 টি আঙুলের সাহায্যে তৈরি করা হয়েছিল (প্রশ্নোত্তর আসলে 13 টি বেসে মেলে)।
paxdiablo

এটা ইঁদুর। প্রতিটি পায়ে 3 টি পায়ের আঙ্গুল, এবং একটি লেজ আপনাকে 13 বেস দেয়
কিথবি

আপনাকে কোনও ঘোষণায় আসলে 'ইনট' লাগবে না, যদিও এটি লেখার পক্ষে এটি অবশ্যই ভাল taste সি সর্বদা ডিফল্টরূপে 'int' প্রকারগুলি ধরে নেয়। চেষ্টা করে দেখুন!
প্রাক্তন

"স্থানীয় মানের 42 ফাইলের স্কোপ সহ" ?? বা এটি পুরো সংকলন ইউনিটের জন্য?
aniliitb10

4

সি ++ এ,

static const int foo = 42;

ধ্রুবকগুলি সংজ্ঞায়িত ও ব্যবহার করার জন্য পছন্দসই উপায়। অর্থাৎ এর চেয়ে এটি ব্যবহার করুন

#define foo 42

কারণ এটি টাইপ-সুরক্ষা সিস্টেমকে বিকৃত করে না।


4

সমস্ত দুর্দান্ত উত্তরের জন্য, আমি একটি ছোট বিশদ যুক্ত করতে চাই:

আপনি যদি প্লাগইন লিখেন (যেমন, ডিএলএল বা .so লাইব্রেরিগুলি একটি সিএডি সিস্টেম দ্বারা বোঝার জন্য), তবে স্থির জীবন রক্ষাকারী যা এই জাতীয় নামের সংঘাতগুলি এড়িয়ে চলে:

  1. সিএডি সিস্টেমটি একটি প্লাগইন এ লোড করে, এতে একটি "কনস্ট ইন ফু = 42;" এটা.
  2. সিস্টেমটি একটি প্লাগিন বি লোড করে, যার "কনট ইন্ট foo = 23" রয়েছে; এটা.
  3. ফলস্বরূপ, প্লাগইন বি foo এর জন্য 42 মানটি ব্যবহার করবে, কারণ প্লাগইন লোডার বুঝতে পারবে যে বাহ্যিক সংযোগের সাথে ইতিমধ্যে একটি "foo" রয়েছে।

আরও খারাপ: 3 ধাপে সংকলক অপ্টিমাইজেশন, প্লাগইন লোড প্রক্রিয়া ইত্যাদির উপর নির্ভর করে আলাদা আচরণ করতে পারে

দুটি প্লাগইনে দুটি সহায়ক ফাংশন (একই নাম, ভিন্ন আচরণ) নিয়ে আমার একবার এই সমস্যাটি হয়েছিল। তাদের স্থির ঘোষণার ফলে সমস্যার সমাধান হয়েছে।


দুটি প্লাগইনগুলির মধ্যে নামের সংঘর্ষের বিষয়ে কিছুটা অদ্ভুত বলে মনে হয়েছিল, যা আমার অনেকগুলি DLL- র জন্য লিঙ্ক ম্যাপটি পরীক্ষা করতে পরিচালিত করেছে যা m_hDfltHeap কে বাহ্যিক সংযোগ সহ একটি হ্যান্ডেল হিসাবে সংজ্ঞায়িত করে। নিশ্চিতভাবেই, লিঙ্কেজ মানচিত্রে _m_hDfltHeap হিসাবে তালিকাভুক্ত সমস্ত বিশ্বের দেখতে ও ব্যবহারের জন্য এটি রয়েছে। আমি এই ফ্যাক্টয়েড সম্পর্কে সব ভুলে যেতে চাই।
ডেভিড এ গ্রে 19

4

C99 / GNU99 স্পেসিফিকেশন অনুযায়ী:

  • static

    • স্টোরেজ-শ্রেণীর নির্দিষ্টকরণকারী

    • ডিফল্টরূপে ফাইল স্তরের স্কোপের অবজেক্টগুলির বাহ্যিক সংযোগ থাকে

    • স্ট্যাটিক স্পেসিফায়ারযুক্ত ফাইল স্তরের স্কোপের অবজেক্টগুলির অভ্যন্তরীণ লিঙ্কেজ রয়েছে
  • const

    • টাইপ-কোয়ালিফায়ার (টাইপের একটি অংশ)

    • তাত্ক্ষণিক বাম উদাহরণগুলিতে কীওয়ার্ড প্রয়োগ করা হয়েছে - যেমন

      • MyObj const * myVar; - যোগ্য অবজেক্টের ধরণের জন্য অযোগ্য পয়েন্টার

      • MyObj * const myVar; - অযোগ্য অবজেক্টের ধরণের কাছে কোয়ালিফাই পয়েন্টার

    • বামতম ব্যবহার - বস্তুর ধরণের ক্ষেত্রে প্রয়োগ করা হয়, পরিবর্তনশীল নয়

      • const MyObj * myVar; - যোগ্য অবজেক্টের ধরণের জন্য অযোগ্য পয়েন্টার

এভাবে

static NSString * const myVar; - অভ্যন্তরীণ সংযোগের সাথে অবিচ্ছিন্ন স্ট্রিংয়ের ধ্রুবক পয়েন্টার।

staticকীওয়ার্ডের অনুপস্থিতি পরিবর্তনশীল নামটিকে বিশ্বব্যাপী করে তুলবে এবং অ্যাপ্লিকেশনটির মধ্যে নাম বিরোধের দিকে নিয়ে যেতে পারে।


4

সি ++ 17 inlineভেরিয়েবল

যদি আপনি "সি ++ কনস্ট স্ট্যাটিক" গুগল করেন তবে আপনি সম্ভবত যা ব্যবহার করতে চান এটি হ'ল সি ++ 17 ইনলাইন ভেরিয়েবল

এই দুর্দান্ত সি ++ 17 বৈশিষ্ট্যটি আমাদের এতে অনুমতি দেয়:

  • প্রতিটি ধ্রুবক জন্য সুবিধামত কেবল একটি একক মেমরি ঠিকানা ব্যবহার করুন
  • এটি একটি হিসাবে সংরক্ষণ করুন constexpr: কীভাবে বহিরাগতকে ঘোষণা করবেন?
  • এটি একটি শিরোলেখ থেকে একক লাইনে করুন

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline constexpr int notmain_i = 42;

const int* notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

const int* notmain_func() {
    return &notmain_i;
}

সংকলন এবং চালান:

g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main

গিটহাব উজানের দিকে

আরও দেখুন: ইনলাইন ভেরিয়েবলগুলি কীভাবে কাজ করে?

ইনলাইন ভেরিয়েবলগুলিতে সি ++ স্ট্যান্ডার্ড

সি ++ স্ট্যান্ডার্ড গ্যারান্টি দেয় যে ঠিকানাগুলি একই হবে। সি ++ 17 এন 4659 স্ট্যান্ডার্ড খসড়া 10.1.6 "ইনলাইন স্পেসিফায়ার":

External বাহ্যিক সংযোগের সাথে একটি ইনলাইন ফাংশন বা ভেরিয়েবলের সমস্ত অনুবাদ ইউনিটে একই ঠিকানা থাকবে।

cppreferences https://en.cppreferences.com/w/cpp/language/inline ব্যাখ্যা করে যে যদি staticদেওয়া না হয় তবে তার বাহ্যিক সংযোগ রয়েছে।

জিসিসির ইনলাইন ভেরিয়েবল বাস্তবায়ন

কীভাবে এটি প্রয়োগ করা হয় তা আমরা পর্যবেক্ষণ করতে পারি:

nm main.o notmain.o

যেটা বহন করে:

main.o:
                 U _GLOBAL_OFFSET_TABLE_
                 U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
                 U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i

notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i

এবং man nmসম্পর্কে বলেছেন u:

"u" প্রতীকটি একটি অনন্য বৈশ্বিক প্রতীক। এটি ELF প্রতীক বাইন্ডিংয়ের মানক সেটটিতে একটি GNU এক্সটেনশন। এই জাতীয় প্রতীকের জন্য ডায়নামিক লিঙ্কার নিশ্চিত করবে যে পুরো প্রক্রিয়াতে এই নাম এবং ব্যবহারের টাইপ সহ কেবল একটি প্রতীক রয়েছে।

সুতরাং আমরা দেখতে পাচ্ছি যে এর জন্য একটি ডেডিকেটেড ইএলএফ এক্সটেনশন রয়েছে।

প্রাক-সি ++ 17: extern const

সি ++ 17 এর আগে এবং সি-তে আমরা একটির সাথে খুব অনুরূপ প্রভাব অর্জন করতে পারি extern constযা একটি একক মেমরি অবস্থান ব্যবহারের দিকে নিয়ে যাবে।

ডাউনসাইডগুলি হ'ল inline:

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.cpp

#include "notmain.hpp"

const int notmain_i = 42;

const int* notmain_func() {
    return &notmain_i;
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

extern const int notmain_i;

const int* notmain_func();

#endif

গিটহাব উজানের দিকে

প্রাক-সি ++ 17 শিরোনাম কেবল বিকল্প

এগুলি externসমাধানের মতো ততটা ভাল নয় , তবে তারা কাজ করে এবং কেবলমাত্র একটি একক মেমরি অবস্থান নেয়:

একটি constexprফাংশন, কারণ constexprবোঝাinline এবং inline পারবেন (বাহিনী) সংজ্ঞা প্রত্যেক অনুবাদ ইউনিট প্রদর্শিত :

constexpr int shared_inline_constexpr() { return 42; }

এবং আমি বাজি ধরেছি যে কোনও শালীন সংকলক কলটি ইনলাইন করবে।

আপনি এখানে constবা constexprস্ট্যাটিক ভেরিয়েবল ব্যবহার করতে পারেন :

#include <iostream>

struct MyClass {
    static constexpr int i = 42;
};

int main() {
    std::cout << MyClass::i << std::endl;
    // undefined reference to `MyClass::i'
    //std::cout << &MyClass::i << std::endl;
}

তবে আপনি এর ঠিকানা নেওয়ার মতো জিনিসগুলি করতে পারবেন না, না হলে এটি অদ্ভুতভাবে ব্যবহৃত হয়ে যায়, এছাড়াও দেখুন: কনস্টেক্সপ্রিক স্ট্যাটিক ডেটা সদস্যদের সংজ্ঞা দেওয়া

সি

সিতে পরিস্থিতি সি ++ প্রাক সি ++ 17 এর মতোই, আমি এখানে একটি উদাহরণ আপলোড করেছি: "স্ট্যাটিক" সি এর অর্থ কী?

মাত্র তফাত হল যে সি ++ হয় constবোঝা staticglobals জন্য, কিন্তু এটা সি না: বনাম `const`` স্ট্যাটিক const` এর সি ++ শব্দার্থবিদ্যা

এটি সম্পূর্ণরূপে ইনলাইন করার কোনও উপায়?

টোডো: কোনও স্মৃতি ব্যবহার না করে ভেরিয়েবলকে সম্পূর্ণরূপে ইনলাইন করার কোনও উপায় আছে কি?

প্রিপ্রোসেসর কী করে তা অনেকটা পছন্দ করে।

এটির কোনওরকম প্রয়োজন হবে:

  • পরিবর্তনশীলের ঠিকানা নেওয়া হয়েছে কিনা তা নিষিদ্ধ বা সনাক্তকরণ
  • ELF অবজেক্ট ফাইলগুলিতে সেই তথ্য যুক্ত করুন, এবং LTO এটির সর্বোত্তম করুন

সম্পর্কিত:

উবুন্টু 18.10, জিসিসি 8.2.0 এ পরীক্ষিত।


2

হ্যাঁ, এটি অন্য মডিউল থেকে একটি মডিউলে একটি পরিবর্তনশীল আড়াল করে। সি ++ এ, আমি যখন এটি .h ফাইল পরিবর্তন করতে চাই না / চাই না যেটি অন্য ফাইলগুলির অপ্রয়োজনীয় পুনর্নির্মাণকে ট্রিগার করবে তখন আমি এটি ব্যবহার করি। এছাড়াও, আমি স্থির আগে রাখি:

static const int foo = 42;

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


2

এই আইএ এর গ্লোবাল অবিচ্ছিন্ন দৃশ্যমান / কেবল সংকলন মডিউল (.cpp ফাইল) এ অ্যাক্সেসযোগ্য। এই উদ্দেশ্যে স্ট্যাটিক ব্যবহার করে বিটিডাব্লু হ্রাস করা হয়েছে। বেনামে নামস্থান এবং একটি এনাম ব্যবহার করা ভাল:

namespace
{
  enum
  {
     foo = 42
  };
}

এটি কম্পাইলারকে একটি ধ্রুবক এবং এই জাতীয় বাধা অপ্টিমাইজেশান হিসাবে foo আচরণ না করার জন্য বাধ্য করবে।
নীল পিপেনব্রিংক

এনামদের মানগুলি সর্বদা স্থির থাকে তাই আমি দেখি না এটি কীভাবে কোনও অপ্টিমাইজেশনে বাধা সৃষ্টি করবে
রোজকোটো

আহ - সত্য .. আমার ত্রুটি। ভেবেছিলেন আপনি একটি সাধারণ ইন-ভেরিয়েবল ব্যবহার করেছেন।
নিলস পিপেনব্রিংক

রোজকোটো, enumএই প্রসঙ্গে কী কী উপকার হবে তা আমি পরিষ্কার করছি না । বিশদ যত্ন? এই ধরনের enumsসাধারণত মান জন্য কোনো স্থান বণ্টন (যদিও আধুনিক কম্পাইলার এই প্রয়োজন হবে না থেকে কম্পাইলার প্রতিরোধ করতে ব্যবহার করা হয় enumতার জন্য হ্যাক) এবং মান পয়েন্টার সৃষ্টি প্রতিরোধ।
কনরাড রুডল্ফ

কনরাড, এই ক্ষেত্রে এনাম ব্যবহার করতে আপনি ঠিক কী সমস্যাটি দেখছেন? যখন আপনার ধ্রুবক ইনটগুলির প্রয়োজন হয় তখন এনামগুলি ব্যবহার করা হয় যা ঠিক এটি।
রোজকোটো

1

এটিকে ব্যক্তিগত করে তোলার অর্থ এটি শিরোনামে প্রদর্শিত হবে। আমি যে কাজ করে "দুর্বলতম" উপায় ব্যবহার করার প্রবণতা রাখি। স্কট মায়ার্সের এই ক্লাসিক নিবন্ধটি দেখুন: http://www.ddj.com/cpp/184401197 (এটি কার্যকারিতা সম্পর্কে, তবে এখানেও প্রয়োগ করা যেতে পারে)।

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