আকারের শৈলী: আকার (ধরণ) বা আকারের ভেরিয়েবল?


22

আমি sizeofমেমরি-সম্পর্কিত ক্রিয়াকলাপগুলির জন্য দুটি স্টাইল ব্যবহার করে দেখেছি (যেমন memsetবা এর মধ্যে malloc):

  • sizeof(type), এবং
  • sizeof variable অথবা sizeof(variable)

আপনি কোনটি পছন্দ করবেন, বা আপনি দুটি শৈলীর মিশ্রণ ব্যবহার করবেন এবং আপনি প্রতিটি শৈলী কখন ব্যবহার করবেন? প্রতিটি শৈলীর উপকারিতা এবং কনসগুলি কী কী এবং আপনি সেগুলি ব্যবহার করার সময়?

উদাহরণস্বরূপ, আমি নীচের জোড়াটি পরিস্থিতিতে দেখতে পাচ্ছি যেখানে একটি শৈলী সাহায্য করে এবং অন্যটি না করে:

আপনি যখন পয়েন্টার ইন্ডিয়ারেশনটি ভুল পান:

type *var;
...
memset(var, 0, sizeof var);    /* oops */

যখন টাইপ পরিবর্তন হয়:

new_type var;    /* changed from old_type to new_type */
...
memset(&var, 0, sizeof(old_type));    /* oops */

উত্তর:


30

আমি পদোন্নতি করা sizeof(variable)উপর sizeof(type)। বিবেচনা:

int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));

বনাম

int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));

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


4
এছাড়াও, আপনি যদি ভেরিয়েবলের ধরণটি পরিবর্তন করেন তবে কোডটি ধাপে ধাপে ধাপে পরিবর্তন করতে হবে। আমি মনে করি এটি যথাসম্ভব ধরণের উপর নির্ভরশীলতার সাথে সঠিক কোডের পক্ষে বেশি ভাল। (আমি ফিরে এসে বড় 16 বিট থেকে 32 বিট রূপান্তর প্রকল্পের দ্বারা প্রভাবিত আছি।)
রোবট

এটি সি অ্যারেগুলিতে কাজ করার পক্ষে পছন্দনীয় যেখানে টাইপডেফ তৈরি করা সাধারণ নয়, তবে চরের অ্যারে [MAX_SIZE] এর মতো জিনিস ব্যবহার করুন;
mattnz

@ ভি 32: ভুল 1: "মাপের (অ্যারে) অ্যারের আকারটি ফিরিয়ে দেয় না ... পয়েন্টারের আকার অ্যারেকে দেয়" - যদি arrayসত্যিকার অর্থে একটি সি অ্যারে sizeof(array)হয় তবে অ্যারে উপাদানগুলি সংরক্ষণ করার জন্য প্রয়োজনীয় বাইটের সংখ্যাটি প্রদান করে । যদি arrayকোনও ক্ষয় হওয়া সি অ্যারের প্রথম উপাদানটির পয়েন্টার হয়, তবে আপনার বিবৃতিটি ধারণ করে। ফাংশন আর্গুমেন্ট হিসাবে সি অ্যারে পাস করা এটি ফাংশনটির পয়েন্টারের মতো দেখায় - এটির আকার হিসাবে এটির অ্যারে হিসাবে প্রমাণিত সমস্ত তথ্য হারিয়ে যায়। এ কারণেই এটি ক্ষয়িষ্ণুভুল 2: "অ্যারে আসলে সি তে বিদ্যমান নেই; পয়েন্টারগুলির জন্য কেবল সিনট্যাকটিক চিনি"।
জোহান জেরেল

9

পছন্দ (যথারীতি সর্বদা) আপনার উদ্দেশ্যটি যথাসম্ভব প্রতিফলিত করা।

একটি বিদ্যমান ভেরিয়েবলের স্মৃতিবিরোধের বিরুদ্ধে কাজ করার অভিপ্রায় কি? যদি তাই হয় তবে ব্যবহার করুন sizeof(variable), এটি যতটা সম্ভব নিবিড়ভাবে দেখায় যে এটি আপনার নিজের যত্নশীল ভেরিয়েবলের স্মৃতি।

এই ধরণের উপর কিছু গণনা করার অভিপ্রায় উদাহরণস্বরূপ, একটি নতুন উদাহরণের জন্য কত স্মৃতি বরাদ্দ করা উচিত তা নির্ধারণ করার জন্য? যদি তাই হয় তবে ব্যবহার করুন sizeof(type)

যে, আমি পছন্দ

struct foo *bar;
bar = (struct foo *) malloc(sizeof(struct foo));

উপর

bar = (struct foo *) malloc(sizeof(*bar));

পরের কেসটি দেখে মনে হচ্ছে আপনি এখনও এমন কোনও পরিবর্তনশীল অ্যাক্সেস করার চেষ্টা করছেন যা এখনও নেই।

অন্যদিকে, আমি পছন্দ করি

char Buffer[256];
memset(Buffer, 0, sizeof(Buffer));

উপর

char Buffer[256];
memset(Buffer, 0, 256 * sizeof(char));

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



আমি সবসময় করি তবে এটি ব্যক্তিগত স্বাদের বিষয়। আমি বিবেচনা করি void *যেগুলিকে অন্য পয়েন্টার ধরণের হিসাবে স্বয়ংক্রিয়ভাবে কাস্ট করা হয় যা একটি ভুল হিসাবে চিহ্নিত করা হয়।
আইদান কুলি

3

আমি ব্যাপকভাবে পছন্দ sizeof(type)করবে sizeof variable। যদিও এটি আপনাকে টাইপ সম্পর্কে আরও চিন্তিত হতে এবং আরও পরিবর্তন করতে বাধ্য করে, এটি আপনাকে পয়েন্টার ইন্ডিয়ারেশন ভুলগুলি এড়াতে সহায়তা করে যা সি এর মধ্যে বাগগুলির সবচেয়ে সাধারণ কারণগুলির মধ্যে রয়েছে

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

এর একটি সুবিধা sizeof variableঅ্যারেগুলির জন্য, তবে অনুশীলনে আমি দেখতে পেয়েছি যে প্রথম / লেনের জোড়া হিসাবে অ্যারেগুলি পাস করা আরও বেশি সাধারণ (যার ক্ষেত্রে কেবল দৈর্ঘ্যটি ব্যবহার করা হয়), পাশাপাশি আকারটি ভুল হওয়াও খুব সহজ plus অ্যারে / পয়েন্টার ক্ষয়, যেমন এই উদাহরণ হিসাবে:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}

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

@ ডিএক্সএম আকারের অপারেন্ডের সাথে যদি এটির মান হয় তবে এটি sizeof var; যদি এটি একটি পয়েন্টার হয় sizeof *var। এটিও এমন কিছু যা লোক ভুল করতে পারে এবং সংকলক আনন্দে অভিযোগ ছাড়াই এটি গ্রহণ করবে। আমি যুক্তি দিচ্ছি যে এই ভুলগুলি sizeof(type)ফর্মের সাথে ভুলগুলির চেয়ে স্পষ্ট করা খুব শক্ত এবং সাধারণ ।
কংগ্রেসবঙ্গাস

1
আপনার উভয় ডান - সি প্রকার এবং আকারের অপারেটর মূলত ভাঙ্গা এবং কখনই নির্ভরযোগ্য হবে না, প্রোগ্রামার হিসাবে আপনি যা কিছু করেন তা এটি ঠিক করতে পারে না।
mattnz

পোস্ট যেমন ট্যাগ হয় C, সি কোড পোস্ট করা আরও তথ্যপূর্ণ যা সি ++ কোড পছন্দ করে mat3_t::mat3_t(...)
chux - মনিকা পুনরায় স্থাপন করুন

0

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

এই জাতীয় সমস্যা নিরসনে ম্যাক্রো, টেমপ্লেট এবং অনুরূপ সরঞ্জামগুলি নগ্ন আকারের পরিবর্তে ব্যবহারের ক্ষেত্রে প্রশিক্ষিত করা স্বাভাবিক।

আমার ক্লিয়ার ম্যাক্রো দেখুন যা নগ্ন মেমসেটের পরিবর্তে একচেটিয়াভাবে ব্যবহৃত হয়। ইন্ডিয়ারেশন টাইপোর ক্ষেত্রে বা যখন কোনও স্ট্রাক্ট সামগ্রী কোনও ভেক্টর বা স্ট্রিং তুলেছে তখন আমার পাছা বেশ কয়েকবার বাঁচিয়েছে ...


এর মতো ম্যাক্রোগুলি সি এর ম্যাক্রো প্রোগ্রামিংকে একটি খারাপ নাম দিয়েছে ......
ম্যাটনজ

@ ম্যাটনজ: দয়া করে আরও ভাল বিকল্পটি দেখান। বাস্তবে কর্মক্ষম প্রোগ্রামগুলি তৈরি করার চেয়ে বিমূর্ত জিনিসগুলির কথা বলা সহজ
বালোগ পাল

1
লিঙ্কযুক্ত ম্যাক্রোটি সি ++, এবং এই পোস্টটিকে 'সি' ট্যাগ করা হয়েছে (তারা বিভিন্ন ভাষা), অ্যাডা আমার পরামর্শ হবে be
mattnz

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

0

ব্যবসায়িক যুক্তি আপনার পছন্দকে সংজ্ঞায়িত করে।

  1. যদি আপনার কোড কোনও নির্দিষ্ট পরিবর্তনশীলকে বোঝায় এবং এই পরিবর্তনশীল ব্যতীত আপনার কোডটি কোনও অর্থবোধ করে না - চয়ন করুন sizeof(var)

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


-1

আকারের উপর নির্ভর করে (পরিবর্তনশীল) সেরা সমাধান হতে পারে। এইভাবে, প্রকারের জন্য সমস্ত প্রবেশপত্র সংশোধন না করে আপনি প্রয়োজনে আপনার পরিবর্তনশীল প্রকারটি পরিবর্তন করতে পারেন। তবে আবার এটি আপনার লক্ষ্যের উপর নির্ভর করে।

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