ম্যাক্রো ব্যবহার করে উত্স ফাইল লাইন গণনা করবেন?


15

কোনও উত্স ফাইলের মধ্যে লাইন গণনা করার জন্য, সি / সি ++ প্রিপ্রসেসর ব্যবহার করে কোনও ম্যাক্রো বা কোনও ধরনের সংকলন-সময়-উপলভ্য মানের মধ্যে এটি কি সম্ভব? যেমন আমি প্রতিস্থাপন করতে পারি MAGIC1, MAGIC2এবং MAGIC3নিম্নলিখিতটিতে, এবং ব্যবহার করার সময় কোনওভাবে 4 মান পেতে MAGIC3পারি?

MAGIC1 // can be placed wherever you like before the relevant 
       // lines - either right before them, or in global scope etc.
foo(); MAGIC2
bar(); MAGIC2
baz(); MAGIC2
quux(); MAGIC2
// ... possibly a bunch of code here; not guaranteed to be in same scope ...
MAGIC3

মন্তব্য:

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

6
আছে একটি ম্যাক্রো বলা__LINE__ যা বর্তমান লাইন সংখ্যা প্রতিনিধিত্ব করে
ForceBru

2
সন্ধান করছেন __COUNTER__এবং / অথবা BOOST_PP_COUNTER?
কামিলকুক

11
আপনার আসল সমস্যাটি সমাধান করার দরকার কী ? আপনার এটার দরকার কেন?
কিছু প্রোগ্রামার ড্যুডে

1
কি এই সাহায্য করেছিল?
ব্যবহারকারী 1810087

1
@ স্পস্কিক: আমি এমন কিছু চাই যা আমি একটি সংকলন-সময় ধ্রুবক হিসাবে ব্যবহার করতে পারি, যেমন বলার জন্য int arr[MAGIC4]এবং আমার কোডের কিছু পূর্ব-গণনা করা বিভাগে লাইন সংখ্যা পেতে।
einpoklum

উত্তর:


15

নেই __LINE__প্রাক প্রসেসর ম্যাক্রো লাইন জন্য হাজির করা হয় যা আপনি একটি পূর্ণসংখ্যা দেয়। আপনি কিছু লাইনে এর মান নিতে পারেন, এবং তারপরে কিছু পরে লাইন এবং তুলনা করতে পারেন।

static const int BEFORE = __LINE__;
foo();
bar();
baz();
quux();
static const int AFTER = __LINE__;
static const int COUNT = AFTER - BEFORE - 1; // 4

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

#define MAGIC2_2(c)
#define MAGIC2(c) MAGIC2_2(c)
static const int BEFORE = __COUNTER__;
void foo(); MAGIC2(__COUNTER__);
void bar(
    int multiple,
    float lines); MAGIC2(__COUNTER__);
void baz(); MAGIC2(__COUNTER__);
void quux(); MAGIC2(__COUNTER__);
static const int AFTER = __COUNTER__;
static const int COUNT = AFTER - BEFORE - 1; // 4

আমি এর প্রাথমিক মানটি গ্রহণ করেছি __COUNTER__কারণ এটি পূর্বে উত্স ফাইলে বা কিছু অন্তর্ভুক্ত শিরক ব্যবহার করা হতে পারে।

সিতে সি ++ এর পরিবর্তে ধ্রুবক ভেরিয়েবলের সীমাবদ্ধতা রয়েছে, সুতরাং enumপরিবর্তে একটি ব্যবহার করা যেতে পারে।

enum MyEnum
{
    FOO = COUNT // C: error: enumerator value for ‘FOO’ is not an integer constant
};

কনস্টের পরিবর্তে enum:

enum {BEFORE = __LINE__};
foo();
bar();
baz();
quux();
enum { COUNT = __LINE__ - BEFORE - 1};
enum MyEnum
{
    FOO = COUNT // OK
};

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

2
__COUNTER__সি বা সি ++ এ স্ট্যান্ডার্ড নয়। আপনি যদি জানেন যে এটি নির্দিষ্ট সংকলকগুলির সাথে কাজ করে তবে সেগুলি উল্লেখ করুন।
পিটার

@ আইনপোকলুম নং, BEFOREএবং AFTERম্যাক্রোস নন
অ্যালান

এই সমাধানটির অ-পাল্টা সংস্করণে একটি সমস্যা রয়েছে: এর আগে এবং পরে কেবল উত্স রেখার মতো একই স্কোপে ব্যবহারযোগ্য। আমার "উদাহরণস্বরূপ" স্নিপেট সম্পাদনা করে প্রতিফলিত করতে যে এটি একটি সমস্যা।
einpoklum

1
@ ব্যবহারকারী 694733 সত্য প্রশ্নটি ট্যাগ করা হয়েছিল [সি ++]। সি enum ধ্রুবক কাজ জন্য।
ফায়ার ল্যান্সার

9

আমি জানি যে ওপির অনুরোধটি ম্যাক্রোগুলি ব্যবহার করার জন্য, তবে আমি এটি করার অন্য একটি উপায় যুক্ত করতে চাই যা ম্যাক্রোগুলি ব্যবহারের সাথে জড়িত না।

সি ++ ২০ এমন source_locationশ্রেণীর সাথে পরিচয় করিয়ে দেয় যা উত্স কোড সম্পর্কে নির্দিষ্ট তথ্য যেমন ফাইলের নাম, লাইন নম্বর এবং ফাংশনের নাম উপস্থাপন করে। এই ক্ষেত্রে আমরা এটি খুব সহজেই ব্যবহার করতে পারি।

#include <iostream>
#include <source_location>

static constexpr auto line_number_start = std::source_location::current().line();
void foo();
void bar();
static constexpr auto line_number_end = std::source_location::current().line();

int main() {
    std::cout << line_number_end - line_number_start - 1 << std::endl; // 2

    return 0;
}

এবং লাইভ উদাহরণ এখানে


ম্যাক্রো ছাড়া ম্যাক্রোগুলির চেয়ে আরও ভাল। তবে - এই পদ্ধতির সাহায্যে আমি কেবল লাইন গণনাটি একই স্কোপে লাইন গণনা করতে পেরেছি I've এছাড়াও - source_locationসি ++ 20 তে পরীক্ষামূলক হতে হবে?
einpoklum

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

ধরুন আমি আপনার পরামর্শটি কোনও ফাংশনের মধ্যে রেখেছি (যেমন গণনা করা রেখাগুলি হ'ল ঘোষণাপত্র নয়) oc এটি কাজ করে - তবে আমার কেবল আছে line_number_startএবং line_number_endসেই সুযোগের মধ্যে অন্য কোথাও নেই। আমি যদি অন্য কোথাও এটি চাই তবে রান-টাইমে এটি পাস করা দরকার - যা উদ্দেশ্যকে হারাতে পারে।
einpoklum

মান এখানে যে উদাহরণ সরবরাহ করে তা একবার দেখুন । যদি এটি ডিফল্ট যুক্তি হয়, তবে এটি এখনও সংকলন-সময়ের অংশ, তাই না?
নিউটক্র্যাকার

হ্যাঁ, তবে এটি line_number_endতার সুযোগের বাইরে সংকলন সময়ে দৃশ্যমান হয় না । আমি ভুল হলে শুধরে.
einpoklum

7

সম্পূর্ণতার জন্য: আপনি যদি MAGIC2প্রতিটি লাইনের পরে যুক্ত করতে ইচ্ছুক হন তবে আপনি এটি ব্যবহার করতে পারেন __COUNTER__:

#define MAGIC2 static_assert(__COUNTER__ + 1, "");

/* some */     MAGIC2
void source(); MAGIC2
void lines();  MAGIC2

constexpr int numberOfLines = __COUNTER__;

int main()
{
    return numberOfLines;
}

https://godbolt.org/z/i8fDLx (রিটার্ন 3)

এর শুরু এবং শেষের মানগুলি সংরক্ষণ করে আপনি এটি পুনরায় ব্যবহারযোগ্য করে তুলতে পারেন __COUNTER__

সামগ্রিকভাবে এটি যদিও জটিল umbers আপনি প্রিপ্রোসেসর নির্দেশিকা বা //মন্তব্যগুলির সাথে শেষ রয়েছে এমন লাইনগুলিও গণনা করতে পারবেন না । আমি __LINE__পরিবর্তে ব্যবহার করব , অন্য উত্তর দেখুন।


1
আপনি কেন ব্যবহার করবেন static_assert?
idclev 463035818

1
উত্স ফাইলটিতে এটি "9" দিয়েছিল যা আমি এটিকে ফেলে দিয়েছি, আপনি __COUNTER__অন্যান্য শিরোনাম ইত্যাদির শুরুতে এখনও শূন্য বলে ধরে নিতে পারেন না , ইত্যাদি এটি ব্যবহার করতে পারে।
ফায়ার ল্যান্সার

আপনাকে __COUNTER__দুবারের মানটি ব্যবহার করতে হবে এবং পার্থক্যটি নিতে হবে
idclev 463035818

1
@ এর আগে অজ্ঞাতনামা 60063535818 __COUNTER__এর নিজস্ব অনুমতি দেওয়া হবে না এবং এটি কোনও কিছুতে প্রসারিত হওয়া দরকার বা এটি গণনা করা হবে না (এটিতে আমি 100% নিয়ম মনে করতে পারি না)।
ফায়ার ল্যান্সার

7

কিছুটা আরও দৃ solution় সমাধান, বিভিন্ন কাউন্টারের জন্য অনুমতি দেওয়া (যতক্ষণ না তারা আন্তঃসংযোগ না দেয় এবং __COUNTER__অন্যান্য কাজের জন্য কোনও ব্যবহার নেই ):

#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)

#define COUNT_THIS_LINE static_assert(__COUNTER__ + 1, "");
#define START_COUNTING_LINES(count_name) \
  enum { EXPAND_THEN_CONCATENATE(count_name, _start) = __COUNTER__ };
#define FINISH_COUNTING_LINES(count_name) \
  enum { count_name = __COUNTER__ - EXPAND_THEN_CONCATENATE(count_name, _start) - 1 };

এটি প্রয়োগের বিশদটি গোপন করে (যদিও এটি তাদের ম্যাক্রোর ভিতরে লুকিয়ে রাখে ...)। এটি @ ম্যাক্সল্যানঘফের উত্তরের একটি সাধারণীকরণ। দ্রষ্টব্য যে __COUNTER__যখন আমরা একটি গণনা শুরু করি তখন এর শূন্যহীন মান থাকতে পারে।

এটি কীভাবে ব্যবহৃত হয়েছে তা এখানে:

START_COUNTING_LINES(ze_count)

int hello(int x) {
    x++;
    /* some */     COUNT_THIS_LINE
    void source(); COUNT_THIS_LINE
    void lines();  COUNT_THIS_LINE
    return x;
}

FINISH_COUNTING_LINES(ze_count)

int main()
{
    return ze_count;
}

এছাড়াও, এটি বৈধ সি - আপনার প্রিপ্রসেসর যদি সমর্থন __COUNTER__করে তবে তা।

গডবোল্টে কাজ করে

যদি আপনি সি ++ ব্যবহার করেন তবে আপনি এই সমাধানটি বৈশ্বিক নামস্থান - এমনকি কাউন্টারগুলির মধ্যে স্থাপন করে namespace macro_based_line_counts { ... }বা অন্যকে দূষিত না করার জন্য এটি পরিবর্তন করতে পারেন namespace detail)


5

আপনার মন্তব্যের ভিত্তিতে আপনি যদি সি বা সি ++ তে একটি (সংকলন-সময়) অ্যারে আকার নির্দিষ্ট করতে চান তবে আপনি এটি করতে পারেন

int array[]; //incomplete type
enum{ LINE0 = __LINE__ }; //enum constants are integer constant expressions
/*lines to be counted; may use array (though not sizeof(array)) */
/*...*/
int array[ __LINE__ - LINE0 ]; //complete the definition of int array[]

যদি আপনাকে sizeof(array)মধ্যবর্তী লাইনের প্রয়োজন হয় তবে আপনি এটিকে একটি স্থির পরিবর্তনশীল রেফারেন্সের সাথে প্রতিস্থাপন করতে পারেন (যদি না এটি একেবারে পূর্ণসংখ্যার ধ্রুবক অভিব্যক্তি হওয়া প্রয়োজন) এবং একটি অনুকূলিতকরণ সংকলককে এটি একইরূপে আচরণ করা উচিত (স্থির পরিবর্তনশীল স্থাপনের প্রয়োজনীয়তা অপসারণ করতে হবে) স্মৃতিতে)

int array[]; static int count;
enum{ LINE0 = __LINE__ }; //enum constants are integer constant expressions
//... possibly use count here
enum { LINEDIFF = __LINE__ - LINE0 }; 
int array[ LINEDIFF ]; /*complete the definition of int array[]*/ 
static int count = LINEDIFF; //fill the count in later

এ- __COUNTER__ভিত্তিক সমাধান (যদি সেই এক্সটেনশানটি উপলব্ধ থাকে) __LINE__তবে কোনও বেস-ভিত্তিক এর বিপরীতে একই কাজ করবে।

constexprসি ++ এর এস-তে পাশাপাশি কাজ করা উচিত enum, তবে enumপ্লেইন সিতেও কাজ করবে (উপরে আমার সমাধানটি একটি সরল সি সমাধান)।


এটি কেবল তখনই কাজ করবে যদি আমার লাইন-কাউন্টের ব্যবহার গণনা করা লাইনের মতো একই স্কোপে থাকে। IIANM। দ্রষ্টব্য আমি আমার প্রশ্নটি সামান্য সম্পাদনা করে জোর দিয়েছিলাম যে এটি একটি সমস্যা হতে পারে।
einpoklum

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

1
রেকর্ডের জন্য, এটি \ প্রভাবিত করে না __LINE__- লাইন বিরতি থাকলে, __LINE__বৃদ্ধি পায়। উদাহরণ 1 , উদাহরণ 2
ম্যাক্স ল্যাংফোফ

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