শূন্য উপাদানগুলির সাথে অ্যারের প্রয়োজন কী?


122

লিনাক্স কার্নেল কোডে আমি নিম্নলিখিত জিনিসটি পেয়েছি যা আমি বুঝতে পারি না।

 struct bts_action {
         u16 type;
         u16 size;
         u8 data[0];
 } __attribute__ ((packed));

কোডটি এখানে: http://lxr.free-electrons.com/source/include/linux/ti_wilink_st.h

শূন্য উপাদান সহ একটি অ্যারের ডেটার প্রয়োজন এবং উদ্দেশ্য কী?


আমি নিশ্চিত নই যে শূন্য-দৈর্ঘ্যের অ্যারে বা
স্ট্রাক

@ হিপ্পিটরেইল, কারণ প্রায়শই যখন কেউ জিজ্ঞাসা করে যে এই স্ট্রাক্টটি কী, তারা জানেন না যে এটিকে "নমনীয় অ্যারে সদস্য" হিসাবে উল্লেখ করা হয়। যদি তারা তা করে থাকে তবে তারা সহজেই তাদের উত্তর খুঁজে পেতে পারত। যেহেতু তারা না, তারা প্রশ্নটি তেমন ট্যাগ করতে পারে না। সে কারণেই আমাদের এ জাতীয় ট্যাগ নেই।
শাহবাজ 1'13

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

5
সদৃশ নয় - আমি প্রথমবার কাউকে অযথা প্রশ্ন বন্ধ করতে দেখিনি। এছাড়াও আমি মনে করি এই প্রশ্নটি এসও নলেজ বেসকে যুক্ত করে।
অনিকেত ইনজে

উত্তর:


139

এটি একবারে কল malloc( kmallocএই ক্ষেত্রে) কল না করে ডাটা ভেরিয়েবল আকারের একটি উপায় । আপনি এটি এর মতো ব্যবহার করবেন:

struct bts_action *var = kmalloc(sizeof(*var) + extra, GFP_KERNEL);

এটি মানক হিসাবে ব্যবহৃত হত না এবং এটি একটি হ্যাক হিসাবে বিবেচিত হত (যেমন অনিকেত বলেছিল), তবে এটি সি 99 তে মানক করা হয়েছিল । এটির জন্য এখন স্ট্যান্ডার্ড ফর্ম্যাটটি হ'ল:

struct bts_action {
     u16 type;
     u16 size;
     u8 data[];
} __attribute__ ((packed)); /* Note: the __attribute__ is irrelevant here */

নোট করুন যে আপনি dataক্ষেত্রের জন্য কোনও আকার উল্লেখ করেন না । আরও উল্লেখ করুন যে এই বিশেষ পরিবর্তনশীলটি কেবল কাঠামোর শেষে আসতে পারে।


সি 99 এ, এই বিষয়টি 6.7.2.1.16 (জোর খনি) এ ব্যাখ্যা করা হয়েছে:

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

বা অন্য কথায়, যদি আপনার কাছে থাকে:

struct something
{
    /* other variables */
    char data[];
}

struct something *var = malloc(sizeof(*var) + extra);

আপনি var->dataসূচকগুলি দিয়ে প্রবেশ করতে পারেন [0, extra)। নোট যেটি sizeof(struct something)শুধুমাত্র অন্যান্য ভেরিয়েবলের জন্য আকার অ্যাকাউন্টিং দেবে, অর্থাত্ data0 এর আকার দেয় ।


এটি আকর্ষণীয়ও হতে পারে যে স্ট্যান্ডার্ড কীভাবে এই mallocজাতীয় নির্মাণের উদাহরণ দেয় (6.7.2.1.17):

struct s { int n; double d[]; };

int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));

একই স্থানে স্ট্যান্ডার্ডের আরও একটি আকর্ষণীয় নোট হ'ল (জোর দেওয়া খনি):

ধরে নিই যে ম্যালোকের কাছে কল সাফল্য পেয়েছে, পি দ্বারা নির্দেশিত বস্তুটি বেশিরভাগ উদ্দেশ্যে, পি হিসাবে ঘোষিত হয়েছে:

struct { int n; double d[m]; } *p;

(এমন পরিস্থিতিতে রয়েছে যেখানে এই সমতাটি ভেঙে গেছে; বিশেষত, সদস্য d এর অফসেটগুলি একই নাও হতে পারে )।


স্পষ্টতই, প্রশ্নের মূল কোডটি এখনও সি 99 (নয় সি 11) তে মানক নয় এবং এখনও একটি হ্যাক হিসাবে বিবেচিত হবে। C99 মানককরণ অবশ্যই অ্যারে বাউন্ড বাদ দিতে পারে।
এমএম

কি [0, extra)?
এসএস আন


36

এটি আসলে একটি হ্যাক, আসলে জিসিসির ( সি 90 ) জন্য ।

একে স্ট্রাক হ্যাকও বলা হয় ।

পরের বার, আমি বলব:

struct bts_action *bts = malloc(sizeof(struct bts_action) + sizeof(char)*100);

এটি বলার সমতুল্য হবে:

struct bts_action{
    u16 type;
    u16 size;
    u8 data[100];
};

এবং আমি এই জাতীয় স্ট্রাক্ট অবজেক্টগুলির যে কোনও সংখ্যা তৈরি করতে পারি।


7

কাঠামোর শেষে ভ্যারিয়েবল-আকারের অ্যারের অনুমতি দেওয়ার জন্য ধারণা। সম্ভবত, bts_actionএকটি স্থির আকারের শিরোনাম ( typeএবং sizeক্ষেত্রগুলি) এবং পরিবর্তনশীল-আকারের dataসদস্য সহ কিছু ডেটা প্যাকেট । এটিকে 0-দৈর্ঘ্যের অ্যারে হিসাবে ঘোষণা করে, এটি অন্য কোনও অ্যারের মতোই সূচকযুক্ত করা যেতে পারে। তারপরে আপনি bts_action1024-বাইট dataআকারের একটি কাঠামো বরাদ্দ করতে চাই , যেমন:

size_t size = 1024;
struct bts_action* action = (struct bts_action*)malloc(sizeof(struct bts_action) + size);

আরও দেখুন: http://c2.com/cgi/wiki?StructHack


2
@Aniket: আমি সম্পূর্ণরূপে নিশ্চিত কোথা থেকে আসে নই যে ধারণা।
শেউ

সি ++ হ্যাঁ, সি তে, প্রয়োজন নেই।
এএমসি

2
@ শিউ, আপনার লেখার স্টাইলটি mallocআপনাকে একাধিকবার পুনরাবৃত্তি করে তোলে এবং যদি কখনও actionপরিবর্তনের ধরণ হয় তবে আপনাকে এটিকে একাধিকবার ঠিক করতে হবে from নিম্নলিখিত দুটি নিজের জন্য তুলনা করুন এবং আপনি জানতে পারবেন: struct some_thing *variable = (struct some_thing *)malloc(10 * sizeof(struct some_thing));বনাম struct some_thing *variable = malloc(10 * sizeof(*variable));দ্বিতীয়টি স্বল্পতর, পরিষ্কার এবং পরিবর্তন করা সহজভাবে সহজ।
শাহবাজ

5

কোডটি বৈধ সি নয় (এটি দেখুন )। লিনাক্স কার্নেলটি সুস্পষ্ট কারণে, বহনযোগ্যতার সাথে সামান্যতম সম্পর্কিত নয়, সুতরাং এটি প্রচুর পরিমাণে অ-মানক কোড ব্যবহার করে।

তারা যা করছে তা অ্যারের আকার 0 সহ একটি জিসিসির অ-মানক এক্সটেনশন A একটি মানক আনুগত্যমূলক প্রোগ্রামটি লিখত u8 data[];এবং এর অর্থ একই জিনিস meant লিনাক্স কার্নেলের লেখকরা দৃশ্যত অযথা জটিল এবং অ-মানক তৈরি করতে পছন্দ করেন, যদি এটির কোনও বিকল্প নিজে প্রকাশ করে option

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

এটিকে অনির্ধারিত থেকে সু-সংজ্ঞায়িত আচরণে পরিবর্তন করতে জিসিসি প্রথমদিকে একটি মানহীন এক্সটেনশন করেছিল। সি 99 স্ট্যান্ডার্ড তখন এই ধারণাটি রূপান্তরিত করেছে এবং যে কোনও আধুনিক সি প্রোগ্রাম তাই ঝুঁকি ছাড়াই এই বৈশিষ্ট্যটি ব্যবহার করতে পারে। এটি C99 / C11 এ নমনীয় অ্যারে সদস্য হিসাবে পরিচিত ।


3
আমি সন্দেহ করি যে "লিনাক্স কার্নেলটি বহনযোগ্যতার সাথে সম্পর্কিত নয়"। সম্ভবত আপনি অন্যান্য সংকলকগুলির কাছে বহনযোগ্যতা বোঝাতে চেয়েছিলেন? এটি সত্য যে এটি জিসিসির বৈশিষ্ট্যগুলির সাথে বেশ জড়িত।
শাহবাজ

3
তবুও, আমি মনে করি এই নির্দিষ্ট কোডের একটি মূলধারার কোড নয় এবং সম্ভবত এটি বাদ পড়েছে কারণ এর লেখক এতে তেমন মনোযোগ দেয়নি। লাইসেন্সটি জানিয়েছে এটি কিছু টেক্সাস যন্ত্রের চালক সম্পর্কে, সুতরাং কার্নেলের মূল প্রোগ্রামাররা এটিতে কোনও মনোযোগ দিয়েছে না unlikely আমি নিশ্চিত যে কার্নেল বিকাশকারীরা নিয়মিত নতুন মান বা নতুন অপ্টিমাইজেশান অনুযায়ী পুরানো কোড আপডেট করে চলেছেন। সবকিছু আপডেট হয়েছে তা নিশ্চিত করার জন্য এটি খুব বড়!
শাহবাজ

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

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

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

1

শূন্য দৈর্ঘ্যের অ্যারের অন্য ব্যবহারটি স্ট্রাক্টের ভিতরে নামযুক্ত লেবেল হিসাবে টাইম স্ট্রাক অফসেট চেক করতে সহায়তা করার জন্য।

ধরুন আপনার কয়েকটি বৃহত স্ট্রাক্ট সংজ্ঞা রয়েছে (একাধিক ক্যাশে লাইন ছড়িয়ে আছে) যা আপনি নিশ্চিত করতে চান যে তারা শুরুতে এবং মাঝখানে যেখানে সীমানাটি অতিক্রম করে সেখানে লাইন সীমানার সাথে সংযুক্ত রয়েছে।

struct example_large_s
{
    u32 first; // align to CL
    u32 data;
    ....
    u64 *second;  // align to second CL after the first one
    ....
};

কোডে আপনি এগুলিকে GCC এক্সটেনশানগুলি ব্যবহার করে ঘোষণা করতে পারেন:

__attribute__((aligned(CACHE_LINE_BYTES)))

তবে আপনি এখনও নিশ্চিত করতে চান যে এটি রানটাইমে প্রয়োগ করা হয়েছে।

ASSERT (offsetof (example_large_s, first) == 0);
ASSERT (offsetof (example_large_s, second) == CACHE_LINE_BYTES);

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

assert (offsetof (one_struct,     <name_of_first_member>) == 0);
assert (offsetof (one_struct,     <name_of_second_member>) == CACHE_LINE_BYTES);
assert (offsetof (another_struct, <name_of_first_member>) == 0);
assert (offsetof (another_struct, <name_of_second_member>) == CACHE_LINE_BYTES);

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

#define CACHE_LINE_ALIGN_MARK(mark) u8 mark[0] __attribute__((aligned(CACHE_LINE_BYTES)))
struct example_large_s
{
    CACHE_LINE_ALIGN_MARK (cacheline0);
    u32 first; // align to CL
    u32 data;
    ....
    CACHE_LINE_ALIGN_MARK (cacheline1);
    u64 *second;  // align to second CL after the first one
    ....
};

তারপরে রানটাইম দৃser় কোডটি বজায় রাখা আরও সহজ হবে:

assert (offsetof (one_struct,     cacheline0) == 0);
assert (offsetof (one_struct,     cacheline1) == CACHE_LINE_BYTES);
assert (offsetof (another_struct, cacheline0) == 0);
assert (offsetof (another_struct, cacheline1) == CACHE_LINE_BYTES);

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