টাইপডিফস এবং # ডেফাইনস


32

আমরা সকলেই এক সময় বা অন্য সময় অবশ্যই typedefs এবং #defines ব্যবহার করেছি । আজ তাদের সাথে কাজ করার সময় আমি একটি বিষয় নিয়ে চিন্তাভাবনা শুরু করি।

intঅন্য নামের সাথে ডেটা টাইপ ব্যবহার করতে নীচের 2 টি পরিস্থিতি বিবেচনা করুন :

typedef int MYINTEGER

এবং

#define MYINTEGER int

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

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


8
তারা কি জন্য ডিজাইন করা হয়েছে তা # নির্ধারণ করুন। কোড লেখার সময় আপনি জানতে পারবেন না এমন বৈশিষ্ট্যের উপর ভিত্তি করে শর্তসাপেক্ষ সংকলন (যেমন ওএস / সংকলক)। অন্যথায় ভাষা নির্মাণগুলি ব্যবহার করুন।
মার্টিন ইয়র্ক

উত্তর:


67

আপনার typedefসাধারণত ম্যাক্রোর প্রয়োজন হয় না এমন কিছু বিজোড় কারণ যদি না থাকে তবে সাধারণত এটিকে অগ্রাধিকার দেওয়া হয়।

ম্যাক্রোগুলি পাঠ্য প্রতিস্থাপন করেন যা কোডের শব্দার্থবিজ্ঞানের ক্ষেত্রে যথেষ্ট সহিংসতা করতে পারে। উদাহরণস্বরূপ, প্রদত্ত:

#define MYINTEGER int

আপনি আইনীভাবে লিখতে পারেন:

short MYINTEGER x = 42;

কারণ short MYINTEGERপ্রসারিত short int

অন্যদিকে, টাইপিডেফ সহ:

typedef int MYINTEGER:

নামটি টাইপেরMYINTEGER অন্য নাম , মূল শব্দ "ইনট" এর কোনও পাঠ্য প্রতিস্থাপন নয়। int

আরও জটিল ধরণের সাথে বিষয়গুলি আরও খারাপ হয়। উদাহরণস্বরূপ, এটি দেওয়া:

typedef char *char_ptr;
char_ptr a, b;
#define CHAR_PTR char*
CHAR_PTR c, d;

a, bএবং cসমস্ত পয়েন্টার হলেও dএটি একটি char, কারণ শেষ লাইনটি এতে প্রসারিত:

char* c, d;

যা সমান

char *c;
char d;

(পয়েন্টার ধরণের টাইপিডগুলি সাধারণত কোনও ভাল ধারণা নয়, তবে এটি বিন্দুটি ব্যাখ্যা করে))

আরেকটি বিজোড় মামলা:

#define DWORD long
DWORD double x;     /* Huh? */

1
আবার দোষারোপকারী পয়েন্টার! :) পয়েন্টার ছাড়াও অন্য কোনও উদাহরণ যেখানে এই জাতীয় ম্যাক্রোগুলি ব্যবহার করা বুদ্ধিমানের নয়?
c0da

2
এমন নয় যে আমি কি কখনও একটি স্থানে একটি ম্যাক্রো ব্যবহার করতে চাই typedef, কিন্তু সঠিক ভাবে একটি ম্যাক্রো যে আর্গুমেন্ট ব্যবহার করা যাই হোক না কেন অনুসরণ সঙ্গে কিছু গড়ে তুলতে: #define CHAR_PTR(x) char *x। এটি কমপক্ষে সংকলককে ভুলভাবে ব্যবহার করা হলে কেভেটচ তৈরি করবে।
ব্লারফ্লার

1
ভুলে যাবেন না:const CHAR_PTR mutable_pointer_to_const_char; const char_ptr const_pointer_to_mutable_char;
জন পূর্ব

3
সংজ্ঞাগুলি ত্রুটি বার্তাগুলিকেও বোঝা যায় না
থমাস বোনিিনি

ম্যাক্রোর অপব্যবহারের যে ব্যথা হতে পারে তার উদাহরণ (যদিও ম্যাক্রো বনাম টাইপডেফগুলির
কিথ থম্পসন

15

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


তবে আমি যেমন প্রশ্নে প্রদত্ত উদাহরণে দেখিয়েছি, একজন টাইপিডেফ এবং # ডেফাইন একই সংখ্যক শব্দ ব্যবহার করে! এছাড়াও, ম্যাক্রোর এই 3 টি শব্দ কোনও বিভ্রান্তির কারণ হবে না, কারণ শব্দগুলি একই, তবে কেবল পুনরায় সাজানো হয়েছে। :)
c0da

2
হ্যাঁ, তবে এটি স্বল্পতা নয়। ম্যাক্রো টাইপডেফিং ছাড়াও আরও কয়েক মিলিয়ন কাজ করতে পারে। তবে ব্যক্তিগতভাবে আমি মনে করি স্কোপিং সবচেয়ে গুরুত্বপূর্ণ।
ট্যামস সেজেলি

2
@ c0da - আপনি টাইপিডেফের জন্য ম্যাক্রো ব্যবহার করবেন না, আপনার টাইপডেফগুলির জন্য টাইপডেফগুলি ব্যবহার করা উচিত। বিভিন্ন প্রতিক্রিয়া দ্বারা চিত্রিত ম্যাক্রোর আসল প্রভাবটি খুব আলাদা হতে পারে।
জোরিস টিমারম্যানস

15

উত্স কোড মূলত সহ বিকাশকারীদের জন্য লেখা। কম্পিউটারগুলি এর একটি সংকলিত সংস্করণ ব্যবহার করে।

এই দৃষ্টিকোণে typedefএকটি অর্থ বহন করে যা #defineতা নয়।


6

কিথ থম্পসনের উত্তরটি খুব ভাল এবং স্কোপিং সম্পর্কিত ট্যামস সেজেলি-র অতিরিক্ত পয়েন্টগুলির সাথে একসাথে আপনার প্রয়োজনীয় সমস্ত পটভূমি সরবরাহ করা উচিত।

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


5

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

typedef void(*fptr_t)(void);

এই একটি টাইপ ঘোষণা fptr_tকোন ধরনের একটি ফাংশন একটি পয়েন্টার void func(void)

আপনি ম্যাক্রো দিয়ে এই ধরণের ঘোষণা করতে পারবেন না। #define fptr_t void(*)(void)স্পষ্টতই কাজ করবে না। আপনাকে এমন অস্পষ্ট কিছু লিখতে হবে #define fptr_t(name) void(*name)(void), যা সি ভাষায় সত্যিকার অর্থে কোনও অর্থ দেয় না, যেখানে আমাদের কোনও নির্মাণকারী নেই।

অ্যারে পয়েন্টারগুলি # ডেফাইন দিয়েও ঘোষণা করা যায় না: typedef int(*arr_ptr)[10];


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


1
আরও ভাল হ'ল ফাংশন এবং অ্যারে পয়েন্টারগুলির সংমিশ্রণগুলি char *(*(*foo())[])();( fooযেমন একটি ফাংশন যা পয়েন্টারকে বিন্যাসে ফাংশনগুলিতে পয়েন্টারগুলির একটি অ্যারেতে পয়েন্টার ফিরিয়ে দেয় char)।
জন বোদে

4

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


2

সংজ্ঞায়নের বিরুদ্ধে সাধারণ যুক্তি ছাড়িয়ে আপনি ম্যাক্রোস ব্যবহার করে এই ফাংশনটি কীভাবে লিখবেন?

template <typename IterType>
typename IterType::value_type Sum(
    const IterType& begin, 
    const IterType& end, 
    const IterType::value_type& initialValue)
{
    typename IterType::value_type result = initialValue;
    for (IterType i = begin; i != end; ++i)
        result += i;

    return result;
}

....

vector<int> values;
int sum = Sum(values.begin(), values.end(), 0);

এটি স্পষ্টতই তুচ্ছ উদাহরণ, তবে সেই ফাংশনটি এমন কোনও প্রকারের পূর্বে পুনরাবৃত্তিযোগ্য ক্রমের উপরে যোগ করতে পারে যা সংযোজন কার্যকর করে * imple এর মতো ব্যবহৃত টাইপিডগুলি জেনেরিক প্রোগ্রামিংয়ের একটি গুরুত্বপূর্ণ উপাদান ।

* আমি কেবল এখানে এটি লিখেছি, আমি এটি পাঠকের জন্য একটি সংক্ষিপ্তসার হিসাবে সংকলন ছেড়ে রেখেছি :-)

সম্পাদনা করুন:

এই উত্তরটি অনেক বিভ্রান্তি ঘটায় বলে মনে হচ্ছে, সুতরাং এটি আরও আঁকতে দাও। আপনি যদি কোনও এসটিএল ভেক্টরের সংজ্ঞাটি ভিতরে দেখতে চান তবে নীচের মতো কিছু দেখতে পাবেন:

template <typename ValueType, typename AllocatorType>
class vector
{
public:
    typedef ValueType value_type;
...
}

স্ট্যান্ডার্ড কন্টেইনারগুলির মধ্যে টাইপডেফগুলির ব্যবহার এই ধরণের রেফারেন্স দেওয়ার জন্য একটি জেনেরিক ফাংশন (উপরে আমি যেভাবে তৈরি করেছি) এর অনুমতি দেয়। "যোগফল" ফাংশনটি ধারক ( std::vector<int>) এর ধরণে প্রেরণ করা হয় , ধারকটির ভিতরে রাখা ধরণের উপর নয় int)। টাইপিডেফ ছাড়া সেই অভ্যন্তরীণ প্রকারটি উল্লেখ করা সম্ভব হবে না।

অতএব, টাইপডিফগুলি আধুনিক সি ++ এর কেন্দ্রবিন্দু এবং ম্যাক্রোসের মাধ্যমে এটি সম্ভব নয়।


typedefম্যাক্রো বনাম ইনলাইন ফাংশন নয়, ম্যাক্রো বনাম সম্পর্কে প্রশ্ন জিজ্ঞাসা করা হয়েছিল ।
বেন ভয়েগট

অবশ্যই, এবং এটি কেবল টাইপিডফের মাধ্যমেই সম্ভব ... মান_প্রকারটি এটাই।
ক্রিস পিটম্যান

এটি কোনও টাইপিড নয়, এটি টেম্পলেট প্রোগ্রামিং। কোনও ফাংশন বা ফান্টেক্টর কোনও ধরণের নয়, তা যত জেনারিক হোক না কেন।

@ লন্ডিন আমি আরও বিশদ যুক্ত করেছি: সাম ফাংশনটি কেবলমাত্র তখনই সম্ভব কারণ স্ট্যান্ডার্ড কনটেইনারগুলি টাইপডেফগুলি যে ধরণের টেম্প্লেটযুক্ত তা প্রকাশ করতে ব্যবহার করে। আমি বলছি না যে সুম একটি টাইপিডেফ। আমি বলছি std :: ভেক্টর <T> :: মান_প্রকার টাইপডেফ । যাচাই করার জন্য কোনও মানক গ্রন্থাগার প্রয়োগের উত্সটি নির্দ্বিধায় দেখতে পান।
ক্রিস পিটম্যান

যথেষ্ট ফর্সা। কেবলমাত্র দ্বিতীয় স্নিপেটটি পোস্ট করা ভাল ছিল।

1

typedefসি ++ দর্শনের সাথে মানানসই: সংকলনের সময়ে সমস্ত সম্ভাব্য চেক / অ্যাসের্টস। #defineকেবল একটি প্রিপ্রোসেসর ট্রিক যা সংকলকটিতে প্রচুর অর্থবোধকে আড়াল করে। কোড সঠিকতার চেয়ে সংকলন কর্মক্ষমতা সম্পর্কে আপনার চিন্তা করা উচিত নয়।

আপনি যখন একটি নতুন ধরণের তৈরি করেন আপনি একটি নতুন "জিনিস" সংজ্ঞায়িত করছেন যা আপনার প্রোগ্রামের ডোমেনটি ম্যানিপুলেট করে। সুতরাং আপনি এই "জিনিসটি" ফাংশন এবং ক্লাস রচনা করতে ব্যবহার করতে পারেন এবং স্থির চেক করার জন্য আপনি আপনার সুবিধার জন্য সংকলকটি ব্যবহার করতে পারেন। যাইহোক, সি ++ সি এর সাথে সামঞ্জস্যপূর্ণ হওয়ায়, অনেকগুলি অন্তর্নিহিত রূপান্তর intএবং অন্তর্নিহিত প্রকারের মধ্যে রয়েছে যা সতর্কতা উত্পন্ন করে না। সুতরাং আপনি এক্ষেত্রে স্ট্যাটিক চেকগুলির সম্পূর্ণ ক্ষমতা পাবেন না। যাইহোক, অন্তর্নিহিত রূপান্তরগুলি খুঁজতে আপনি এটির typedefসাথে প্রতিস্থাপন করতে পারেন enum। উদাহরণস্বরূপ: যদি আপনি থাকেন typedef int Age;তবে আপনি এটির সাথে প্রতিস্থাপন করতে পারবেন enum Age { };এবং আপনি Ageএবং এর মধ্যে অন্তর্নিহিত রূপান্তর দ্বারা সমস্ত ধরণের ত্রুটি পাবেন int

আরেকটি জিনিস: typedefক এর ভিতরে থাকতে পারে namespace


1

টাইপিডেফের পরিবর্তে সংজ্ঞা ব্যবহার করা অন্য গুরুত্বপূর্ণ দিকের অধীনে সমস্যায় পড়ছে, এবং টাইপ বৈশিষ্ট্যের ধারণা। বিভিন্ন শ্রেণি বিবেচনা করুন (স্ট্যান্ডার্ড পাত্রে ভাবেন) যার মধ্যে তাদের নির্দিষ্ট টাইপডাইফগুলি সংজ্ঞায়িত করা হয়। আপনি টাইপডেফগুলি উল্লেখ করে জেনেরিক কোড লিখতে পারেন। এর উদাহরণগুলির মধ্যে সাধারণ ধারক প্রয়োজনীয়তা (সি ++ স্ট্যান্ডার্ড 23.2.1 [ধারক। প্রয়োজনীয়তা.জেনারাল]) অন্তর্ভুক্ত রয়েছে

X::value_type
X::reference
X::difference_type
X::size_type

এগুলি সমস্ত ম্যাক্রোর সাথে জেনেরিক উপায়ে প্রকাশযোগ্য নয় কারণ এটি স্কোপ করা হয়নি।


1

আপনার ডিবাগারে এর প্রভাবগুলি ভুলে যাবেন না। কিছু ডিবাগারগুলি # ডিফাইনকে খুব ভালভাবে পরিচালনা করে না। আপনি যে ডিবাগারটি ব্যবহার করেন তাতে উভয়ের সাথেই খেলুন। মনে রাখবেন, আপনি এটি লেখার চেয়ে বেশি সময় ব্যয় করবেন।


-2

"# ডেফাইন" আপনি যা লিখেছেন তা প্রতিস্থাপন করবে, টাইপডিফ টাইপ তৈরি করবে। তাই আপনি যদি গ্রাহক টাইপ রাখতে চান - টাইপডিফ ব্যবহার করুন। আপনার যদি ম্যাক্রোর প্রয়োজন হয় - সংজ্ঞায়িত করুন।


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