আমি প্যারামিটারের মাধ্যমে সি স্ট্রাক্টগুলি শুরু করতে পারি, না ফেরতের মান দ্বারা? [বন্ধ]


33

আমি যে সংস্থাটিতে কাজ করি সেগুলি তাদের ডেটা স্ট্রাকচারের সমস্তটির সূচনা এভাবে শুরু করে:

//the structure
typedef struct{
  int a,b,c;  
} Foo;

//the initialize function
InitializeFoo(Foo* const foo){
   foo->a = x; //derived here based on other data
   foo->b = y; //derived here based on other data
   foo->c = z; //derived here based on other data
}

//initializing the structure  
Foo foo;
InitializeFoo(&foo);

আমি আমার স্ট্রাকগুলি এভাবে শুরু করার চেষ্টা করে কিছুটা ধাক্কা ফিরে পেয়েছি:

//the structure
typedef struct{
  int a,b,c;  
} Foo;

//the initialize function
Foo ConstructFoo(int a, int b, int c){
   Foo foo;
   foo.a = a; //part of parameter input (inputs derived outside of function)
   foo.b = b; //part of parameter input (inputs derived outside of function)
   foo.c = c; //part of parameter input (inputs derived outside of function)
   return foo;
}

//initialize (or construct) the structure
Foo foo = ConstructFoo(x,y,z);

একে অপরের থেকে কি একটা সুবিধা আছে?
আমার কোনটি করা উচিত এবং আমি কীভাবে এটি আরও ভাল অনুশীলন হিসাবে ন্যায়সঙ্গত করব?


4
@gnat এটি স্ট্রাক্ট ইনিশিয়েশন সম্পর্কে একটি স্পষ্ট প্রশ্ন। এই থ্রেডটিতে আমি একই বিশেষ নকশার সিদ্ধান্তের জন্য প্রয়োগ দেখতে চাই একই যুক্তিযুক্ত কিছু উত্সাহিত করি।
ট্রেভর হিকি

2
@ জেফফ্রে আমরা সি তে আছি, সুতরাং বাস্তবে আমাদের কোনও পদ্ধতি থাকতে পারে না। এটি সর্বদা মানগুলির সরাসরি সেট নয়। কখনও কখনও একটি স্ট্রাক্টের সূচনাটি হ'ল মানগুলি (কোনওভাবে) পাওয়া এবং কাঠামোটি আরম্ভ করার জন্য কিছু যুক্তি সম্পাদন করে।
ট্রেভর হিকি 16

1
@ জ্যাকসবিবি আমি পেয়েছি "আপনি যে প্রতিটি উপাদান তৈরি করেন তা অন্যের চেয়ে আলাদা হবে the
ট্রেভর হিকি

1
@ ট্রেভর হিকি InitializeFoo()একটি নির্মাতা । সি ++ কনস্ট্রাক্টরের পার্থক্য কেবল হ'ল, thisপয়েন্টারটি স্পষ্টভাবে না দিয়ে স্পষ্টতই পাস করা হয়েছে। সংকলিত কোড InitializeFoo()এবং একটি সম্পর্কিত সি ++ Foo::Foo()হুবহু একই।
মাস

2
আরও ভাল বিকল্প: সি ওভার সি ++ ব্যবহার বন্ধ করুন। Autowin।
টমাস এডিং

উত্তর:


25

২ য় পন্থায় আপনার কখনই অর্ধ-আরম্ভিত ফু থাকবে না। সমস্ত নির্মাণ এক জায়গায় রাখা আরও বোধগম্য এবং সুস্পষ্ট জায়গা বলে মনে হয়।

তবে ... 1 ম উপায়টি এতটা খারাপ নয়, এবং প্রায়শই অনেকগুলি ক্ষেত্রে ব্যবহার করা হয় (এমনকি নির্ভরতা-ইনজেকশনের সর্বোত্তম উপায় নিয়েও আলোচনা হয়, হয় আপনার 1 ম উপায়ের মতো সম্পত্তি-ইনজেকশন, বা 2 য়ের মতো কনস্ট্রাক্টর ইঞ্জেকশন)) । দুটিও ভুল নয়।

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


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

4
@ ট্র্যাভের হিকি: আসলে আমি বলব যে উদাহরণগুলি আপনি দিয়েছেন তার মধ্যে দুটি মূল পার্থক্য রয়েছে - (1) একটিতে ফাংশনটি কাঠামোর দিকে সূচনা করার জন্য একটি পয়েন্টারটি দেওয়া হয়, এবং অন্যটিতে এটি একটি প্রাথমিক কাঠামো ফেরত দেয়; (২) একটিতে সূচনা পরামিতিগুলি ফাংশনে প্রেরণ করা হয় এবং অন্যটিতে সেগুলি অন্তর্নিহিত। আপনি (2) সম্পর্কে আরও জিজ্ঞাসা করছেন বলে মনে হয় তবে এখানে উত্তরগুলি (1) তে মনোনিবেশ করছে। আপনি এই বিষয়টি স্পষ্ট করতে চাইতে পারেন - আমার সন্দেহ হয় বেশিরভাগ লোকেরা স্পষ্টত পরামিতি এবং একটি পয়েন্টার ব্যবহার করে দুজনের একটি হাইব্রিডের সুপারিশ করবে:void SetupFoo(Foo *out, int a, int b, int c)
স্মরণিকা

1
প্রথম দৃষ্টিভঙ্গি কীভাবে "অর্ধ-প্রাথমিক" Fooকাঠামোর দিকে পরিচালিত করবে? প্রথম পদ্ধতির সমস্ত জায়গায় এক জায়গায় সমস্ত সূচনাও সম্পাদন করে। (অথবা আপনি একটি বিবেচনা করা হয় উন সক্রিয়া Foostruct হয় হতে "অর্ধ সক্রিয়া"?)
jamesdlin

1
@ জেমসডলিন যেসব ক্ষেত্রে ফু তৈরি হয় এবং ইনিশিয়ালফুটি দুর্ঘটনাক্রমে মিস হয়। এটি একটি দীর্ঘ বিবরণ টাইপ না করে ২ - পর্বের সূচনাটি বর্ণনা করার জন্য কেবল বক্তৃতার একটি চিত্র ছিল। আমি অনুভব করেছি অভিজ্ঞ বিকাশকারী ধরণের লোকেরা বুঝতে পারে।
gbjbaanb

22

উভয় পন্থা একটি একক ফাংশন কল মধ্যে প্রারম্ভিককরণ কোড বান্ডিল। এ পর্যন্ত সব ঠিকই.

তবে, দ্বিতীয় পদ্ধতির সাথে দুটি বিষয় রয়েছে:

  1. দ্বিতীয়টি আসলে ফলাফলযুক্ত বস্তুটি তৈরি করে না, এটি স্ট্যাকের উপর অন্য একটি বস্তুর সূচনা করে, যা চূড়ান্ত অবজেক্টে অনুলিপি করা হয়। এই কারণেই আমি দ্বিতীয় পদ্ধতিরটিকে কিছুটা নিকৃষ্ট হিসাবে দেখতে চাই। আপনি যে পুশ-ব্যাক পেয়েছেন তা সম্ভবত এই বহিরাগত অনুলিপিটির কারণে।

    এটি আরও খারাপ হয় যখন আপনি ক্লাস Derivedনেন Foo(স্ট্রাক্টগুলি মূলত সিতে অবজেক্ট অরিয়েন্টেশনের জন্য ব্যবহৃত হয়): দ্বিতীয় পদ্ধতির সাথে ফাংশনটি ConstructDerived()কল করবে ConstructFoo(), ফলস্বরূপ অস্থায়ী Fooবস্তুটিকে কোনও Derivedবস্তুর সুপারক্লাস স্লটে অনুলিপি করে ; Derivedঅবজেক্টের সূচনা শেষ করুন ; কেবল ফেরত নেওয়ার ফলে ফলাফলটি আবার অনুলিপি করা হয়। তৃতীয় স্তর যুক্ত করুন, এবং সম্পূর্ণ জিনিস সম্পূর্ণ হাস্যকর হয়ে যায়।

  2. দ্বিতীয় পদ্ধতির সাথে, ConstructClass()ফাংশনগুলির নির্মাণাধীন অবজেক্টের ঠিকানার অ্যাক্সেস নেই। এটি নির্মাণের সময় অবজেক্টগুলিকে সংযুক্ত করা অসম্ভব করে তোলে, কারণ যখন প্রয়োজন হয় যখন কোনও বস্তু কলব্যাকের জন্য অন্য কোনও অবজেক্টের সাথে নিজেকে নিবন্ধিত করে।


সবশেষে, সমস্ত structsসম্পূর্ণ ক্লাসে ক্লাস হয় না। কিছু structsকার্যকরভাবে এই ভেরিয়েবলগুলির মানগুলিতে কোনও অভ্যন্তরীণ সীমাবদ্ধতা ছাড়াই কেবল একত্রিত করে ভেরিয়েবলগুলির একগুচ্ছ বান্ডিল করে। typedef struct Point { int x, y; } Point;এটির একটি ভাল উদাহরণ হবে। এই জন্য একটি ইনিশিয়ালাইজার ফাংশন ব্যবহার ওভারকিল মনে হয়। এই ক্ষেত্রে, যৌগিক আক্ষরিক বাক্য গঠনটি সুবিধাজনক হতে পারে (এটি C99):

Point = { .x = 7, .y = 9 };

অথবা

Point foo(...) {
    //other stuff

    return (Point){ .x = n, .y = n*n };
}


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

3
সংকলক ব্যবহারকারী যে কোনও ব্যক্তির উচিত তারা যে কোডটি লিখেছেন তা সংকলক দ্বারা রূপান্তরিত হবে expect যদি না তারা একটি হার্ডওয়্যার সি ইন্টারপ্রেটার চালাচ্ছেন, অন্যথায় বিশ্বাস করা সহজ হলেও এমনকি তারা যে কোডটি লিখেছেন তা কোড তারা কার্যকর করবে না। যদি তারা তাদের সংকলকটি বুঝতে পারে তবে তারা এলিজেন্স বুঝতে পারবে এবং বাইনারিটিতে int x = 3;স্ট্রিংটি না সঞ্চয় করা থেকে আলাদা x। ঠিকানা এবং উত্তরাধিকারের পয়েন্টগুলি ভাল; এলিসনের ধরে নেওয়া ব্যর্থতা বোকামি।
ইয়াক্ক

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

@ ইয়াক্ক: উদাহরণ রয়েছে, উদাহরণস্বরূপ, এটি একটি সংকলককে বলবে যে "নিম্নলিখিত চলকগুলি নিম্নলিখিত কোডের প্রসারিত সময়ে নিরাপদে রেজিস্টারে রাখা যেতে পারে" এবং সেই সাথে অপ্রটিমকরণের unsigned charঅনুমতি ছাড়া অন্য কোনও ধরণের ব্লক-অনুলিপি করার উপায় এক সাথে প্রোগ্রামার প্রত্যাশাগুলি পরিষ্কার করার সময়, কঠোর Aliasing নিয়ম অপর্যাপ্ত হবে।
supercat

1

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

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

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


3
আপনার শেষ পয়েন্ট: রেফারেন্স হিসাবে পাস করা পয়েন্টারের অনুলিপি রাখতে কোনও ফাংশন থামাতে সি ++ তে কিছুই নেই, ফাংশনটি কেবলমাত্র অবজেক্টের ঠিকানা নিতে পারে take রেফারেন্সটি অন্য কোনও অবজেক্ট তৈরির জন্য এটি নিখরচায় রয়েছে যা সেই রেফারেন্স ধারণ করে (কোনও নগ্ন পয়েন্টার তৈরি হয়নি)। তবুও, পয়েন্টার অনুলিপি বা অবজেক্টের রেফারেন্সটি যে বিষয়টিকে তারা দেখায় সেটিকে আউটলাইভ করতে পারে, একটি ঝুঁকিপূর্ণ পয়েন্টার / রেফারেন্স তৈরি করে। সুতরাং রেফারেন্স-সুরক্ষা সম্পর্কে বিষয়টি বেশ নিঃশব্দ।
প্রচারক mas

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

1

"আউটপুট-প্যারামিটার" শৈলীর পক্ষে একটি যুক্তি হ'ল এটি ফাংশনটিকে একটি ত্রুটি কোড ফেরত দিতে দেয়।

struct MyStruct {
    int x;
    char *y;
    // ...
};

int MyStruct_init(struct MyStruct *out) {
    // ...
    char *c = malloc(n);
    if (!c) {
        return -1;
    }
    out->y = c;
    return 0;  // Success!
}

কিছু সম্পর্কিত স্ট্রাক্ট বিবেচনা করে, যদি সূচনাটি তাদের কোনওটির জন্য ব্যর্থ হতে পারে, তবে তাদের সকলেরই ধারাবাহিকতার জন্য আউট-প্যারামিটার শৈলী ব্যবহার করা ভাল।


1
যদিও এক মাত্র সেট করতে পারে errno
Deduplicator

0

আমি অনুমান করছি যে আপনার ফোকাস আউটপুট প্যারামিটার বনাম রিটার্নের মাধ্যমে ইনিশিয়ালাইজেশনের মাধ্যমে ইনিশিয়ালাইজেশনের দিকে রয়েছে, নির্মাণের যুক্তিগুলি কীভাবে সরবরাহ করা হয় তার ক্ষেত্রে তাত্পর্য নয়।

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


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