এনামের নামগুলিকে স্ট্রিং-এ রূপান্তর করবেন কীভাবে


92

গণিতে নামগুলি সি-তে স্ট্রিংয়ে রূপান্তর করার কোনও সম্ভাবনা আছে কি?

উত্তর:


188

একটি উপায়, প্রিপ্রোসেসরকে কাজটি করাতে making এটি আপনার এনাম এবং স্ট্রিংগুলি সিঙ্কে রয়েছে তাও নিশ্চিত করে।

#define FOREACH_FRUIT(FRUIT) \
        FRUIT(apple)   \
        FRUIT(orange)  \
        FRUIT(grape)   \
        FRUIT(banana)  \

#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,

enum FRUIT_ENUM {
    FOREACH_FRUIT(GENERATE_ENUM)
};

static const char *FRUIT_STRING[] = {
    FOREACH_FRUIT(GENERATE_STRING)
};

প্রিপ্রসেসর সম্পন্ন হওয়ার পরে, আপনার কাছে এটি হবে:

enum FRUIT_ENUM {
    apple, orange, grape, banana,
};

static const char *FRUIT_STRING[] = {
    "apple", "orange", "grape", "banana",
};

তাহলে আপনি এর মতো কিছু করতে পারেন:

printf("enum apple as a string: %s\n",FRUIT_STRING[apple]);

যদি ব্যবহারের ক্ষেত্রে আক্ষরিকভাবে কেবল এনাম নামটি মুদ্রণ করা হয় তবে নিম্নলিখিত ম্যাক্রোগুলি যুক্ত করুন:

#define str(x) #x
#define xstr(x) str(x)

তারপরে:

printf("enum apple as a string: %s\n", xstr(apple));

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

#define foo apple

int main() {
    printf("%s\n", str(foo));
    printf("%s\n", xstr(foo));
}

আউটপুটটি হবে:

foo
apple

এটি কারণ অ্যাপ্লিকেশন হিসাবে প্রসারিত করার চেয়ে str ইনপুট foo আরও শক্তিশালী করবে। এক্সস্ট্রি ব্যবহার করে ম্যাক্রো প্রসারণটি প্রথমে করা হয়, তারপরে ফলাফলটি স্ট্রিংফাই করা হয়।

আরও তথ্যের জন্য স্ট্রিংফিকেশন দেখুন ।


4
এটি নিখুঁত, তবে আমি আসলে কী ঘটছে তা বুঝতে অক্ষম। : O
p0l এরিস

উপরের ক্ষেত্রে কীভাবে একটি স্ট্রিংকে এনুমে রূপান্তর করতে পারে?
p0l এরিস

এটি অর্জনের কয়েকটি উপায় রয়েছে, আপনি কী অর্জন করার চেষ্টা করছেন তার উপর নির্ভর করে?
টেরেন্স এম

4
আপনি যদি আপেল এবং কমলা দিয়ে নাম #define GENERATE_ENUM(ENUM) PREFIX##ENUM,
স্থানটি

4
যারা এই পোস্টটি জুড়ে আসেন, একটি প্রোগ্রামে বিভিন্ন আইটেম গণনা করার জন্য ম্যাক্রো তালিকা ব্যবহারের এই পদ্ধতিটিকে অনানুষ্ঠানিকভাবে "এক্স ম্যাক্রোস" বলা হয়।
লন্ডিন

27

আপনার কাছে এমন পরিস্থিতি রয়েছে:

enum fruit {
    apple, 
    orange, 
    grape,
    banana,
    // etc.
};

আমি এটিকে হেডার ফাইলটিতে রাখতে চাই যেখানে এনাম সংজ্ঞায়িত করা হয়েছে:

static inline char *stringFromFruit(enum fruit f)
{
    static const char *strings[] = { "apple", "orange", "grape", "banana", /* continue for rest of values */ };

    return strings[f];
}

4
আমার জীবনের জন্য আমি দেখতে পাচ্ছি না এটি কীভাবে সাহায্য করে। আপনি এটি আরও সুস্পষ্ট করতে কিছুটা প্রসারিত করতে পারেন।
ডেভিড হেফারনান

4
ঠিক আছে, কিভাবে এটি সাহায্য করে? আপনি কি বলছেন যে এটি টাইপ করা enumToString(apple)চেয়ে টাইপ করা সহজ "apple"? এটি কোথাও যে কোনও ধরণের সুরক্ষা আছে বলে মনে হয় না। যদি আপনি এখানে কিছু প্রস্তাব না পান তবে আপনি এখানে যা বলছেন তা অর্থহীন এবং কেবলমাত্র কোডটিকে সাফ করাতে সফল হয়।
ডেভিড হেফারনান

4
ঠিক আছে, আমি এখন দেখতে। ম্যাক্রো আমার দৃষ্টিতে বোগাস এবং আমি আপনাকে এটি মুছে ফেলার পরামর্শ দিচ্ছি।
ডেভিড হেফারনান

4
মন্তব্য ম্যাক্রো সম্পর্কে আলোচনা। এটা কোথায়?
এম কে ..

4
এটি বজায় রাখতেও অসুবিধে হয়। যদি আমি একটি নতুন এনাম .োকান তবে আমার এটির সদৃশ হয়ে ডাব্লিকেট করতে স্মরণে রাখতে হবে correct
ফ্যাবিও

14

এটি সরাসরি অর্জন করার কোনও সহজ উপায় নেই। তবে পি 99 এর ম্যাক্রো রয়েছে যা আপনাকে স্বয়ংক্রিয়ভাবে এ জাতীয় ফাংশন তৈরি করতে দেয়:

 P99_DECLARE_ENUM(color, red, green, blue);

একটি শিরোনাম ফাইল, এবং

 P99_DEFINE_ENUM(color);

একটি সংকলনের ইউনিটে (.c ফাইল) এর পরে কৌশলটি করা উচিত, উদাহরণস্বরূপ ফাংশনটি তখন ডাকা হবে color_getname


আমি এই লিবিয়াকে কীভাবে টানবো?
জনিটেক্স

14

আমি একটি সি প্রাক প্রসেসর কৌতুক যে একই কাজ করছে পাওয়া ছাড়া ডেডিকেটেড অ্যারের স্ট্রিং ঘোষণা (: উত্স http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/c_preprocessor_applications_en )।

সিক্যুয়ালিয়াল এনামগুলি

স্টেফান রামের উদ্ভাবনের পরে, অনুক্রমিক এনামগুলি (সূচকটি স্পষ্টভাবে উল্লেখ না করে, যেমন enum {foo=-1, foo1 = 1}) এই প্রতিভা ট্রিক হিসাবে অনুধাবন করা যেতে পারে:

#include <stdio.h>

#define NAMES C(RED)C(GREEN)C(BLUE)
#define C(x) x,
enum color { NAMES TOP };
#undef C

#define C(x) #x,    
const char * const color_name[] = { NAMES };

এটি নিম্নলিখিত ফলাফল দেয়:

int main( void )  { 
    printf( "The color is %s.\n", color_name[ RED ]);  
    printf( "There are %d colors.\n", TOP ); 
}

রঙটি লাল।
3 টি রঙ আছে।

অ-অনুক্রমিক এনামগুলি

যেহেতু আমি ত্রুটি কোড সংজ্ঞাটি অ্যারে স্ট্রিং হিসাবে মানচিত্র করতে চেয়েছিলাম, যাতে আমি ত্রুটি কোডে কাঁচা ত্রুটি সংজ্ঞা যুক্ত করতে পারি (উদাহরণস্বরূপ "The error is 3 (LC_FT_DEVICE_NOT_OPENED)."), আমি কোডটি সেভাবে প্রসারিত করেছি যাতে আপনি সহজেই সংশ্লিষ্ট এনাম মানগুলির জন্য প্রয়োজনীয় সূচকটি নির্ধারণ করতে পারেন :

#define LOOPN(n,a) LOOP##n(a)
#define LOOPF ,
#define LOOP2(a) a LOOPF a LOOPF
#define LOOP3(a) a LOOPF a LOOPF a LOOPF
#define LOOP4(a) a LOOPF a LOOPF a LOOPF a LOOPF
#define LOOP5(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF
#define LOOP6(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF
#define LOOP7(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF
#define LOOP8(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF
#define LOOP9(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF


#define LC_ERRORS_NAMES \
    Cn(LC_RESPONSE_PLUGIN_OK, -10) \
    Cw(8) \
    Cn(LC_RESPONSE_GENERIC_ERROR, -1) \
    Cn(LC_FT_OK, 0) \
    Ci(LC_FT_INVALID_HANDLE) \
    Ci(LC_FT_DEVICE_NOT_FOUND) \
    Ci(LC_FT_DEVICE_NOT_OPENED) \
    Ci(LC_FT_IO_ERROR) \
    Ci(LC_FT_INSUFFICIENT_RESOURCES) \
    Ci(LC_FT_INVALID_PARAMETER) \
    Ci(LC_FT_INVALID_BAUD_RATE) \
    Ci(LC_FT_DEVICE_NOT_OPENED_FOR_ERASE) \
    Ci(LC_FT_DEVICE_NOT_OPENED_FOR_WRITE) \
    Ci(LC_FT_FAILED_TO_WRITE_DEVICE) \
    Ci(LC_FT_EEPROM_READ_FAILED) \
    Ci(LC_FT_EEPROM_WRITE_FAILED) \
    Ci(LC_FT_EEPROM_ERASE_FAILED) \
    Ci(LC_FT_EEPROM_NOT_PRESENT) \
    Ci(LC_FT_EEPROM_NOT_PROGRAMMED) \
    Ci(LC_FT_INVALID_ARGS) \
    Ci(LC_FT_NOT_SUPPORTED) \
    Ci(LC_FT_OTHER_ERROR) \
    Ci(LC_FT_DEVICE_LIST_NOT_READY)


#define Cn(x,y) x=y,
#define Ci(x) x,
#define Cw(x)
enum LC_errors { LC_ERRORS_NAMES TOP };
#undef Cn
#undef Ci
#undef Cw
#define Cn(x,y) #x,
#define Ci(x) #x,
#define Cw(x) LOOPN(x,"")
static const char* __LC_errors__strings[] = { LC_ERRORS_NAMES };
static const char** LC_errors__strings = &__LC_errors__strings[10];

এই উদাহরণে, সি প্রিপ্রসেসর নিম্নলিখিত কোড উত্পন্ন করবে :

enum LC_errors { LC_RESPONSE_PLUGIN_OK=-10,  LC_RESPONSE_GENERIC_ERROR=-1, LC_FT_OK=0, LC_FT_INVALID_HANDLE, LC_FT_DEVICE_NOT_FOUND, LC_FT_DEVICE_NOT_OPENED, LC_FT_IO_ERROR, LC_FT_INSUFFICIENT_RESOURCES, LC_FT_INVALID_PARAMETER, LC_FT_INVALID_BAUD_RATE, LC_FT_DEVICE_NOT_OPENED_FOR_ERASE, LC_FT_DEVICE_NOT_OPENED_FOR_WRITE, LC_FT_FAILED_TO_WRITE_DEVICE, LC_FT_EEPROM_READ_FAILED, LC_FT_EEPROM_WRITE_FAILED, LC_FT_EEPROM_ERASE_FAILED, LC_FT_EEPROM_NOT_PRESENT, LC_FT_EEPROM_NOT_PROGRAMMED, LC_FT_INVALID_ARGS, LC_FT_NOT_SUPPORTED, LC_FT_OTHER_ERROR, LC_FT_DEVICE_LIST_NOT_READY, TOP };

static const char* __LC_errors__strings[] = { "LC_RESPONSE_PLUGIN_OK", "" , "" , "" , "" , "" , "" , "" , "" "LC_RESPONSE_GENERIC_ERROR", "LC_FT_OK", "LC_FT_INVALID_HANDLE", "LC_FT_DEVICE_NOT_FOUND", "LC_FT_DEVICE_NOT_OPENED", "LC_FT_IO_ERROR", "LC_FT_INSUFFICIENT_RESOURCES", "LC_FT_INVALID_PARAMETER", "LC_FT_INVALID_BAUD_RATE", "LC_FT_DEVICE_NOT_OPENED_FOR_ERASE", "LC_FT_DEVICE_NOT_OPENED_FOR_WRITE", "LC_FT_FAILED_TO_WRITE_DEVICE", "LC_FT_EEPROM_READ_FAILED", "LC_FT_EEPROM_WRITE_FAILED", "LC_FT_EEPROM_ERASE_FAILED", "LC_FT_EEPROM_NOT_PRESENT", "LC_FT_EEPROM_NOT_PROGRAMMED", "LC_FT_INVALID_ARGS", "LC_FT_NOT_SUPPORTED", "LC_FT_OTHER_ERROR", "LC_FT_DEVICE_LIST_NOT_READY", };

নিম্নলিখিত প্রয়োগকারীর ক্ষমতাগুলির ফলাফল:

LC_erferences__strings [-1] ==> LC_erferences__strings [LC_RESPONSE_GENERIC_ERROR] ==> "LC_RESPONSE_GENERIC_ERROR"


ভাল লাগল এটি ঠিক আমি যা খুঁজছিলাম এবং এটির জন্য ব্যবহার করছি। একই ত্রুটি :)
মরবিন

6

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

এনাম এবং স্ট্রিংগুলির একটি অ্যারে ব্যবহার করা

enum fruit                                                                   
{
    APPLE = 0, 
    ORANGE, 
    GRAPE,
    BANANA,
    /* etc. */
    FRUIT_MAX                                                                                                                
};   

const char * const fruit_str[] =
{
    [BANANA] = "banana",
    [ORANGE] = "orange",
    [GRAPE]  = "grape",
    [APPLE]  = "apple",
    /* etc. */  
};

দ্রষ্টব্য: fruit_strঅ্যারেতে থাকা স্ট্রিংগুলি এনাম আইটেমগুলির মতো একই ক্রমে ঘোষণা করতে হবে না।

এটি কিভাবে ব্যবহার করতে

printf("enum apple as a string: %s\n", fruit_str[APPLE]);

একটি সংকলন সময় চেক যোগ করা

আপনি যদি একটি স্ট্রিং ভুলে যেতে ভয় পান তবে আপনি নিম্নলিখিত চেকটি যুক্ত করতে পারেন:

#define ASSERT_ENUM_TO_STR(sarray, max) \                                       
  typedef char assert_sizeof_##max[(sizeof(sarray)/sizeof(sarray[0]) == (max)) ? 1 : -1]

ASSERT_ENUM_TO_STR(fruit_str, FRUIT_MAX);

এনাম আইটেমের পরিমাণ অ্যারেতে থাকা স্ট্রিংয়ের পরিমাণের সাথে মেলে না তবে সংকলনের সময় একটি ত্রুটি জানানো হবে।


2

এনামকে বৈধতা না দেওয়ার মতো একটি কাজ একটি ক্ষুদ্র ক্ষুদ্র বিপজ্জনক। আমি একটি সুইচ স্টেটমেন্ট ব্যবহার করার পরামর্শ দিচ্ছি। আরেকটি সুবিধা হ'ল এটি এনামগুলিতে ব্যবহার করা যেতে পারে যা মানগুলি সংজ্ঞায়িত করেছে, উদাহরণস্বরূপ পতাকাগুলির জন্য যেখানে মানগুলি 1,2,4,8,16 ইত্যাদি etc.

আপনার সমস্ত এনাম স্ট্রিংগুলি এক অ্যারেতে একসাথে রাখুন: -

static const char * allEnums[] = {
    "Undefined",
    "apple",
    "orange"
    /* etc */
};

শিরোনাম ফাইলটিতে সূচকগুলি সংজ্ঞায়িত করুন: -

#define ID_undefined       0
#define ID_fruit_apple     1
#define ID_fruit_orange    2
/* etc */

এটি করার ফলে বিভিন্ন সংস্করণ উত্পাদন করা সহজ হয়, উদাহরণস্বরূপ যদি আপনি অন্যান্য প্রোগ্রামের সাথে আপনার প্রোগ্রামের আন্তর্জাতিক সংস্করণ তৈরি করতে চান।

ম্যাক্রো ব্যবহার করে, শিরোলেখ ফাইলটিতেও: -

#define CASE(type,val) case val: index = ID_##type##_##val; break;

একটি স্যুইচ স্টেটমেন্ট দিয়ে একটি ফাংশন তৈরি করুন, এটি একটি ফিরে আসবে const char *কারণ স্ট্রিং স্ট্যাটিক কনসেটস: -

const char * FruitString(enum fruit e){

    unsigned int index;

    switch(e){
        CASE(fruit, apple)
        CASE(fruit, orange)
        CASE(fruit, banana)
        /* etc */
        default: index = ID_undefined;
    }
    return allEnums[index];
}

যদি উইন্ডোজের সাথে প্রোগ্রামিং হয় তবে ID_ মানগুলি সংস্থান মান হতে পারে।

(যদি সি ++ ব্যবহার করে থাকেন তবে সমস্ত ফাংশনের একই নাম থাকতে পারে।

string EnumToString(fruit e);

)


2

স্ট্রিং অ্যারেটি ইনস্ট্যান্ট করতে ডিজাইনারদের উপর ভিত্তি করে হোকিওর "নন-সিক্যুশিয়াল এনামস" উত্তরের একটি সহজ বিকল্প:

#define NAMES C(RED, 10)C(GREEN, 20)C(BLUE, 30)
#define C(k, v) k = v,
enum color { NAMES };
#undef C

#define C(k, v) [v] = #k,    
const char * const color_name[] = { NAMES };

-2

আমি সাধারণত এটি করি:

#define COLOR_STR(color)                            \
    (RED       == color ? "red"    :                \
     (BLUE     == color ? "blue"   :                \
      (GREEN   == color ? "green"  :                \
       (YELLOW == color ? "yellow" : "unknown"))))   

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