গণিতে নামগুলি সি-তে স্ট্রিংয়ে রূপান্তর করার কোনও সম্ভাবনা আছে কি?
উত্তর:
একটি উপায়, প্রিপ্রোসেসরকে কাজটি করাতে 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 আরও শক্তিশালী করবে। এক্সস্ট্রি ব্যবহার করে ম্যাক্রো প্রসারণটি প্রথমে করা হয়, তারপরে ফলাফলটি স্ট্রিংফাই করা হয়।
আরও তথ্যের জন্য স্ট্রিংফিকেশন দেখুন ।
#define GENERATE_ENUM(ENUM) PREFIX##ENUM,
আপনার কাছে এমন পরিস্থিতি রয়েছে:
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];
}
enumToString(apple)
চেয়ে টাইপ করা সহজ "apple"
? এটি কোথাও যে কোনও ধরণের সুরক্ষা আছে বলে মনে হয় না। যদি আপনি এখানে কিছু প্রস্তাব না পান তবে আপনি এখানে যা বলছেন তা অর্থহীন এবং কেবলমাত্র কোডটিকে সাফ করাতে সফল হয়।
এটি সরাসরি অর্জন করার কোনও সহজ উপায় নেই। তবে পি 99 এর ম্যাক্রো রয়েছে যা আপনাকে স্বয়ংক্রিয়ভাবে এ জাতীয় ফাংশন তৈরি করতে দেয়:
P99_DECLARE_ENUM(color, red, green, blue);
একটি শিরোনাম ফাইল, এবং
P99_DEFINE_ENUM(color);
একটি সংকলনের ইউনিটে (.c ফাইল) এর পরে কৌশলটি করা উচিত, উদাহরণস্বরূপ ফাংশনটি তখন ডাকা হবে color_getname
।
আমি একটি সি প্রাক প্রসেসর কৌতুক যে একই কাজ করছে পাওয়া ছাড়া ডেডিকেটেড অ্যারের স্ট্রিং ঘোষণা (: উত্স 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"
আপনার এনাম এবং স্ট্রিংগুলি সিঙ্কে রয়েছে তা নিশ্চিত করার জন্য আপনাকে প্রিপ্রোসেসরে নির্ভর করতে হবে না। আমার কাছে ম্যাক্রোগুলি ব্যবহার করে কোডটি আরও শক্ত করে পড়া।
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);
এনাম আইটেমের পরিমাণ অ্যারেতে থাকা স্ট্রিংয়ের পরিমাণের সাথে মেলে না তবে সংকলনের সময় একটি ত্রুটি জানানো হবে।
এনামকে বৈধতা না দেওয়ার মতো একটি কাজ একটি ক্ষুদ্র ক্ষুদ্র বিপজ্জনক। আমি একটি সুইচ স্টেটমেন্ট ব্যবহার করার পরামর্শ দিচ্ছি। আরেকটি সুবিধা হ'ল এটি এনামগুলিতে ব্যবহার করা যেতে পারে যা মানগুলি সংজ্ঞায়িত করেছে, উদাহরণস্বরূপ পতাকাগুলির জন্য যেখানে মানগুলি 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);
)
স্ট্রিং অ্যারেটি ইনস্ট্যান্ট করতে ডিজাইনারদের উপর ভিত্তি করে হোকিওর "নন-সিক্যুশিয়াল এনামস" উত্তরের একটি সহজ বিকল্প:
#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 };
আমি সাধারণত এটি করি:
#define COLOR_STR(color) \
(RED == color ? "red" : \
(BLUE == color ? "blue" : \
(GREEN == color ? "green" : \
(YELLOW == color ? "yellow" : "unknown"))))