ধ্রুবকগুলির জন্য # ডেফাইন বা কনস্ট ইন্ট ব্যবহার করা কি ভাল?


26

আরডুইনো একটি বিজোড় সংকর, যেখানে এম্বেড করা বিশ্বে কিছু সি ++ কার্যকারিতা ব্যবহৃত হয় —তিহ্যগতভাবে একটি সি পরিবেশ। আসলে, অনেকগুলি আরডুইনো কোড যদিও খুব সি হিসাবে রয়েছে is

সি tradition #defineতিহ্যগতভাবে ধ্রুবকগুলির জন্য গুলি ব্যবহার করে। এইটার জন্য অনেক কারণ আছে:

  1. আপনি অ্যারে মাপ ব্যবহার করে সেট করতে পারবেন না const int
  2. আপনি const intকেস স্টেটমেন্ট লেবেল হিসাবে ব্যবহার করতে পারবেন না (যদিও এটি কিছু সংকলকগুলিতে কাজ করে)
  3. আপনি constঅন্যের সাথে আরম্ভ করতে পারবেন না const

আপনি আরও যুক্তির জন্য এই প্রশ্নটি স্ট্যাকওভারফ্লোতে দেখতে পারেন check

সুতরাং, আমাদের আরডুইনোর জন্য কী ব্যবহার করা উচিত? আমি ঝুঁকির দিকে ঝুঁকছি #define, তবে কিছু কোড ব্যবহার করে দেখছি constএবং কিছু মিশ্রণটি ব্যবহার করছে using


একটি ভাল অপ্টিমাইজার এটি রট দেবে
র‌্যাচেট ফ্রিক

3
সত্যি? আমি দেখতে পাই না যে কোনও সংকলক কীভাবে টাইপ সুরক্ষার মতো জিনিসগুলি সমাধান করতে চলেছে, অ্যারের দৈর্ঘ্য সংজ্ঞায়িত করতে ব্যবহার করতে সক্ষম না হওয়া ইত্যাদি।
সাইবার্বিবনস

আমি রাজী. এছাড়াও, আপনি যদি নীচে আমার উত্তরটি লক্ষ্য করেন, আমি প্রমাণ করি যে এমন পরিস্থিতি রয়েছে যখন আপনি সত্যিই জানেন না কোন প্রকারটি ব্যবহার করতে হবে, তাই #defineসুস্পষ্ট পছন্দ। আমার উদাহরণটি এনালগ পিনের নামকরণে - এ 5 এর মতো। এটির জন্য উপযুক্ত কোনও প্রকার নেই যা কেবলমাত্র ব্যবহার হিসাবে ব্যবহার করা যেতে পারে constএবং কেবলমাত্র #defineঅর্থটি ব্যাখ্যা করার আগে সংকলকটিকে এটি পাঠ্য ইনপুট হিসাবে স্থান দেওয়া উচিত।
এসডসোলার

উত্তর:


21

এটি লক্ষ করা জরুরী যে সি এবং সি ++ তে অভিন্ন আচরণ const intকরে না , সুতরাং প্রকৃতপক্ষে মূল প্রশ্নে এবং পিটার ব্লুমফিল্ডসের বিস্তৃত উত্তরে এর বিরুদ্ধে যে কয়েকটি আপত্তি প্রমাণিত হয়েছে তা বৈধ নয়:

  • সি ++ এ const intধ্রুবকগুলি সময় মানগুলি সংকলন করে এবং অ্যারের সীমা নির্ধারণ করতে , কেস লেবেল ইত্যাদির জন্য ব্যবহৃত হতে পারে used
  • const intঅবিচ্ছিন্নভাবে কোনও স্টোরেজ দখল করে না। আপনি যদি তাদের ঠিকানা না নেন বা তাদের বাহ্যিক ঘোষণা না করেন তবে তাদের সাধারণত একটি সংকলন সময় অস্তিত্ব থাকবে।

তবে পূর্ণসংখ্যার ধ্রুবকগুলির জন্য এটি প্রায়শই একটি (নামযুক্ত বা বেনামে) ব্যবহার করা ভাল enum। আমি প্রায়শই এটি পছন্দ করি কারণ:

  • এটি সি এর সাথে পিছনে সামঞ্জস্যপূর্ণ
  • এটি প্রায় প্রকারের মতো নিরাপদ const int(প্রতিটি বিট যেমন সি ++ তে নিরাপদ)।
  • এটি সম্পর্কিত ধ্রুবককে দলবদ্ধ করার একটি প্রাকৃতিক উপায় সরবরাহ করে।
  • এমনকি এগুলি আপনি কিছু পরিমাণ নেমস্পেস নিয়ন্ত্রণের জন্য ব্যবহার করতে পারেন।

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


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

1
"সুতরাং প্রকৃতপক্ষে এর বিরুদ্ধে বেশ কয়েকটি আপত্তি যেটিকে মূল প্রশ্নে চিহ্নিত করা হয়েছে" - কেন তারা মূল প্রশ্নে বৈধ নয়, যেমন বলা হয়েছে যে এগুলি সি এর প্রতিবন্ধকতা?
সাইবারবিবন্স

@ সাইবার্বিবনস আরডুইনো সি ++ এর উপর ভিত্তি করে তৈরি হয়েছে, সুতরাং কেন কেবলমাত্র সীমাবদ্ধতা প্রাসঙ্গিক হবে তা আমার কাছে পরিষ্কার নয় (যদি কোনও কারণে আপনার কোডটি সি এর সাথেও সামঞ্জস্যপূর্ণ না হয় তবে)।
মাইক্রোথেরিয়ন

3
@ পিটারআর ব্লুমফিল্ড, অতিরিক্ত স্টোরেজ প্রয়োজন হয় না এমন ধ্রুবক সম্পর্কে আমার বক্তব্য সীমাবদ্ধ ছিল const int। আরও জটিল ধরণের জন্য, আপনি ঠিক বলেছেন যে সঞ্চয়স্থান বরাদ্দ হতে পারে, তবে তবুও, আপনি এ এর ​​চেয়ে খারাপ হওয়ার সম্ভাবনা কম #define
মাইক্রোথেরিয়ন

7

সম্পাদনা: মাইক্রোথেরিয়ান একটি দুর্দান্ত উত্তর দেয় যা আমার কিছু পয়েন্ট এখানে সংশোধন করে বিশেষত মেমরির ব্যবহার সম্পর্কে।


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

তবে আরও অনেক পরিস্থিতি রয়েছে যেখানে অগত্যা একটিও 'সঠিক' উত্তর নেই। এখানে কিছু গাইডলাইন রয়েছে যা আমি অনুসরণ করব:

প্রকারের সুরক্ষা
একটি সাধারণ প্রোগ্রামিং পয়েন্ট অফ ভিউ থেকে, constভেরিয়েবলগুলি সাধারণত পছন্দনীয় (যেখানে সম্ভব হয়)। এর মূল কারণ হ'ল টাইপ-সেফটি।

#define(প্রিপ্রোসেসর ম্যাক্রো) কোডের প্রতিটি স্থানে আক্ষরিক মানটিকে সরাসরি অনুলিপি করে প্রতিটি ব্যবহারকে স্বাধীন করে তোলে। এটি হাইপোথিটিক্যালি ফলস্বরূপ তৈরি করতে পারে, কারণ এটি কীভাবে / কোথায় ব্যবহার করা হয়েছে তার উপর নির্ভর করে প্রকারটি ভিন্নভাবে সমাধান করা যেতে পারে।

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

এটির জন্য একটি সম্ভাব্য কর্মক্ষেত্র হ'ল একটি এর মধ্যে সুস্পষ্ট কাস্ট বা টাইপ-প্রত্যয় অন্তর্ভুক্ত করা #define। উদাহরণ স্বরূপ:

#define THE_ANSWER (int8_t)42
#define NOT_QUITE_PI 3.14f

এই পদ্ধতিটি সম্ভবত এটির ব্যবহারের উপর নির্ভর করে কিছু ক্ষেত্রে সিনট্যাক্স সমস্যা সৃষ্টি করতে পারে।

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

  • const ভেরিয়েবলগুলি (সাধারণত) অন্যান্য সমস্ত ভেরিয়েবলের সাথে এসআরএমে সংরক্ষণ করা হবে।
  • ব্যবহৃত আক্ষরিক মানগুলি #defineপ্রায়শই স্কেচের পাশাপাশি প্রোগ্রাম স্পেসে (ফ্ল্যাশ মেমরি) সংরক্ষণ করা হবে।

(দ্রষ্টব্য যে এখানে বিভিন্ন জিনিস রয়েছে যা কিছু কীভাবে এবং কোথায় সঞ্চিত হয় যেমন সংকলক কনফিগারেশন এবং অপ্টিমাইজেশানকে প্রভাবিত করতে পারে))

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

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

ডকুমেন্টেশনে প্রদত্ত সাধারণ ফর্মটি নিম্নরূপ:

dataType variableName[] PROGMEM = {dataInt0, dataInt1, dataInt3...}; 

স্ট্রিং টেবিলগুলি কিছুটা জটিল, তবে ডকুমেন্টেশনের পুরো বিশদ রয়েছে।


1

একটি নির্দিষ্ট ধরণের ভেরিয়েবলের জন্য যা এক্সিকিউশন চলাকালীন পরিবর্তিত হয় না, হয় সাধারণত ব্যবহার করা যেতে পারে।

ভেরিয়েবলগুলিতে থাকা ডিজিটাল পিন নম্বরগুলির জন্য, হয় কাজ করতে পারে - যেমন:

const int ledPin = 13;

তবে একটি পরিস্থিতি যেখানে আমি সর্বদা ব্যবহার করি #define

এটি এনালগ পিন নম্বরগুলি সংজ্ঞায়িত করা, যেহেতু তারা বর্ণমালা হয়।

নিশ্চিত, আপনি হার্ড-কোড হিসেবে পিন নম্বর পারেন a2, a3ইত্যাদি সব প্রোগ্রাম সর্বত্র এবং কম্পাইলার তাদের সাথে কি করতে জানতে হবে। তারপরে আপনি যদি পিন পরিবর্তন করেন তবে প্রতিটি ব্যবহার পরিবর্তন করা দরকার।

তদুপরি, আমি সর্বদা আমার পিনের সংজ্ঞাগুলি এক জায়গায় শীর্ষে রাখতে চাই, সুতরাং প্রশ্নটি হয়ে ওঠে যে কোন ধরণের constপিন হিসাবে সংজ্ঞায়িত করা উপযুক্ত হবে A5

সেই ক্ষেত্রে আমি সর্বদা ব্যবহার করি #define

ভোল্টেজ বিভাজকের উদাহরণ:

//
//  read12     Reads Voltage of 12V Battery
//
//        SDsolar      8/8/18
//
#define adcInput A5    // Voltage divider output comes in on Analog A5
float R1 = 120000.0;   // R1 for voltage divider input from external 0-15V
float R2 =  20000.0;   // R2 for voltage divider output to ADC
float vRef = 4.8;      // 9V on Vcc goes through the regulator
float vTmp, vIn;
int value;
.
.
void setup() {
.
// allow ADC to stabilize
value=analogRead(adcPin); delay(50); value=analogRead(adcPin); delay(50);
value=analogRead(adcPin); delay(50); value=analogRead(adcPin); delay(50);
value=analogRead(adcPin); delay(50); value=analogRead(adcPin);
.
void loop () {
.
.
  value=analogRead(adcPin);
  vTmp = value * ( vRef / 1024.0 );  
  vIn = vTmp / (R2/(R1+R2)); 
 .
 .

সমস্ত সেটআপ ভেরিয়েবলগুলি শীর্ষে রয়েছে এবং adcPinসংকলনের সময় ব্যতীত এর মানটিতে কোনও পরিবর্তন হবে না ।

কী ধরণের তা নিয়ে কোনও উদ্বেগ নেই adcPin। এবং একটি ধ্রুবক সঞ্চয় করতে বাইনারিটিতে কোনও অতিরিক্ত র্যাম ব্যবহার করা হয় না।

সংকলক সংকলনের আগে adcPinস্ট্রিংয়ের প্রতিটি উদাহরণকে সহজেই প্রতিস্থাপন করে A5


একটি আকর্ষণীয় আরডিনো ফোরাম থ্রেড রয়েছে যা সিদ্ধান্ত নেওয়ার অন্যান্য উপায় নিয়ে আলোচনা করে:

# ডিফাইন বনাম কনস্ট ভেরিয়েবল (আরডুইনো ফোরাম)

Excertps:

কোড প্রতিস্থাপন:

#define FOREVER for( ; ; )

FOREVER
 {
 if (serial.available() > 0)
   ...
 }

ডিবাগিং কোড:

#ifdef DEBUG
 #define DEBUG_PRINT(x) Serial.println(x)
#else
 #define DEBUG_PRINT(x)
#endif

সংজ্ঞা trueএবং falseবুলিয়ান হিসাবে র্যাম সংরক্ষণ করতে

Instead of using `const bool true = 1;` and same for `false`

#define true (boolean)1
#define false (boolean)0

এটির অনেকগুলি ব্যক্তিগত পছন্দকে নেমে আসে তবে এটি স্পষ্ট যে #defineআরও বহুমুখী।


একই পরিস্থিতিতে, ক এর constচেয়ে বেশি র‌্যাম ব্যবহার করবে না #define। এবং অ্যানালগ পিনগুলির জন্য, আমি তাদের এগুলি সংজ্ঞায়িত করব const uint8_t, যদিও const intকোনও পার্থক্য নেই।
এডগার বোনেট

আপনি "লিখেছেন একটি constআসলে আরো র্যাম [...] পর্যন্ত এটা আসলে ব্যবহার করা হয় ব্যবহার করে না "। আপনি আমার বক্তব্যটি মিস করেছেন: বেশিরভাগ সময়, এ constব্যবহার করা হলেও র‍্যাম ব্যবহার করে না । তারপরে, " এটি একটি মাল্টিপাস সংকলক "। সবচেয়ে গুরুত্বপূর্ণ, এটি একটি অনুকূলিতকরণ সংকলক। যখনই সম্ভব, ধ্রুবকগুলি তাত্ক্ষণিক ক্রিয়াকলাপগুলিতে অনুকূলিত হয় ।
এডগার বোনেট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.