C enum से मान के बजाय टेक्स्ट प्रिंट करें


87
int main()
{

  enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

  Days TheDay;

  int j = 0;

  printf("Please enter the day of the week (0 to 6)\n");

  scanf("%d",&j);

  TheDay = Days(j);

  //how to PRINT THE VALUES stored in TheDay

  printf("%s",TheDay);  //   isnt working

  return 0;
}

आपका अपेक्षित आउटपुट इसके लिए स्ट्रिंग "संडे" इत्यादि को प्रिंट करना है?
गांगेय कॉवॉय

जवाबों:


104

C में गणना ऐसे नंबर हैं जिनके आपके कोड के अंदर सुविधाजनक नाम हैं। वे तार नहीं हैं, और स्रोत कोड में उन्हें सौंपे गए नाम आपके कार्यक्रम में संकलित नहीं हैं, और इसलिए वे रनटाइम के लिए सुलभ नहीं हैं।

एकमात्र तरीका यह है कि आप जो चाहते हैं वह एक फ़ंक्शन को स्वयं लिखना है जो एक स्ट्रिंग में गणना मूल्य का अनुवाद करता है। जैसे (यहाँ यह मानकर कि आप enum Daysबाहर की घोषणा को आगे बढ़ाते हैं main):

const char* getDayName(enum Days day) 
{
   switch (day) 
   {
      case Sunday: return "Sunday";
      case Monday: return "Monday";
      /* etc... */
   }
}

/* Then, later in main: */
printf("%s", getDayName(TheDay));

वैकल्पिक रूप से, आप एक सरणी को मानचित्र के रूप में उपयोग कर सकते हैं, जैसे

const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };

/* ... */

printf("%s", dayNames[TheDay]);

लेकिन यहां आप संभवतः Sunday = 0सुरक्षित रहने के लिए एन्यूमरेशन में असाइन करना चाहते हैं ... मुझे यकीन नहीं है कि अगर सी मानक को 0 से एन्यूमरेशन शुरू करने के लिए कंपाइलर्स की आवश्यकता होती है, हालांकि सबसे ज्यादा (मुझे यकीन है कि कोई व्यक्ति इस बात की पुष्टि या खंडन करने के लिए टिप्पणी करेगा) )।


3
अरे, तुम मुझे सरणी समाधान के लिए हराया। : पी लेकिन हाँ, एनम हमेशा 0 से शुरू होते हैं जब तक आप एक अलग मूल्य निर्दिष्ट नहीं करते हैं।
कैसाब्लांका

1
यदि मैं अनुक्रमणिका के रूप में गणना का उपयोग करने पर भरोसा कर रहा था, तो मैं वास्तव में प्रत्येक को स्पष्ट रूप से संख्या देना पसंद करूंगा। मानकों के अनुसार अनावश्यक, लेकिन एक समूह संकलक के रूप में मेरे अनुभव में निम्नलिखित मानकों पर सबसे अच्छा नहीं रहा है।
५० पर jdmichal

3
C मानक कहता है, "यदि standard rst एन्यूमरेटर के पास कोई = नहीं है, तो इसके एन्यूमरेशन स्थिरांक का मान 0 है"। लेकिन यह स्पष्ट होने के लिए कुछ भी चोट नहीं करता है।
माइकल बूर

17
मत भूलना कि C99 के साथ आप कर सकते हैं const char* dayNames[] = {[Sunday] = "Sunday", [Monday] = "Monday", [Tuesday] = "Tuesday", /* ... etc ... */ };। आप जानते हैं, यदि सप्ताह के दिन फिर से शुरू हो जाते हैं, या आप तय करते हैं कि सोमवार सप्ताह का पहला दिन है।
तैम शेफेयर

2
@ user3467349 यह (प्रीप्रोसेसर स्ट्रिंगिफिकेशन) # स्ट्रिंग में # का अनुसरण करने वाले सिंबल को बदल देता है। तो, हाँ, #Monday "सोमवार" में बदल जाएगा, लेकिन Days TheDay = Monday; printf("%s", #TheDay);"TheDay" को प्रिंट करेगा।
टायलर मैकहेनरी

29

मैं कुछ इस तरह का उपयोग करें:

"EnumToString.h" फ़ाइल में:

#undef DECL_ENUM_ELEMENT
#undef DECL_ENUM_ELEMENT_VAL
#undef DECL_ENUM_ELEMENT_STR
#undef DECL_ENUM_ELEMENT_VAL_STR
#undef BEGIN_ENUM
#undef END_ENUM

#ifndef GENERATE_ENUM_STRINGS
    #define DECL_ENUM_ELEMENT( element ) element,
    #define DECL_ENUM_ELEMENT_VAL( element, value ) element = value,
    #define DECL_ENUM_ELEMENT_STR( element, descr ) DECL_ENUM_ELEMENT( element )
    #define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_VAL( element, value )
    #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
    #define END_ENUM( ENUM_NAME ) ENUM_NAME; \
            const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
    #define BEGIN_ENUM( ENUM_NAME) const char * GetString##ENUM_NAME( enum tag##ENUM_NAME index ) {\
        switch( index ) { 
    #define DECL_ENUM_ELEMENT( element ) case element: return #element; break;
    #define DECL_ENUM_ELEMENT_VAL( element, value ) DECL_ENUM_ELEMENT( element )
    #define DECL_ENUM_ELEMENT_STR( element, descr ) case element: return descr; break;
    #define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_STR( element, descr )

    #define END_ENUM( ENUM_NAME ) default: return "Unknown value"; } } ;

#endif

फिर किसी भी हेडर फ़ाइल में आप एनम घोषणा, दिन enum.h बनाते हैं

#include "EnumToString.h"

BEGIN_ENUM(Days)
{
    DECL_ENUM_ELEMENT(Sunday) //will render "Sunday"
    DECL_ENUM_ELEMENT(Monday) //will render "Monday"
    DECL_ENUM_ELEMENT_STR(Tuesday, "Tuesday string") //will render "Tuesday string"
    DECL_ENUM_ELEMENT(Wednesday) //will render "Wednesday"
    DECL_ENUM_ELEMENT_VAL_STR(Thursday, 500, "Thursday string") // will render "Thursday string" and the enum will have 500 as value
    /* ... and so on */
}
END_ENUM(MyEnum)

फिर EnumToString.c नामक फ़ाइल में:

#include "enum.h"

#define GENERATE_ENUM_STRINGS  // Start string generation

#include "enum.h"             

#undef GENERATE_ENUM_STRINGS   // Stop string generation

इसके बाद main.c में:

int main(int argc, char* argv[])
{
    Days TheDay = Monday;
    printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "1 - Monday"

    TheDay = Thursday;
    printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "500 - Thursday string"

    return 0;
}

यह "स्वचालित रूप से" उत्पन्न करेगा किसी भी enums के लिए तार इस तरह से घोषित किया और "EnumToString.c" में शामिल किया गया


4
इसके माध्यम से पढ़ने के लिए बदसूरत है, लेकिन आपके पास डेटा दोहराव नहीं है। (बाकी सभी के विपरीत।) मुझे पसंद है कि क्या मुझे यह पसंद है।
किम रीस

1
कोई डेटा दोहराव और शायद सबसे अच्छा रखरखाव / लचीलेपन के साथ अजीब रचनात्मक समाधान के लिए +1, लेकिन येच! मुझे लगता है कि मैं अभी भी सिर्फ चार चार * [] मार्ग जाना चाहता हूँ।
प्रकट करें

4
हाँ, स्थिरता बहुत बढ़िया है! सप्ताह के दिनों में बदलाव होने पर अपडेट करना वास्तव में आसान है! </ sarcasm> वैसे, यह स्थानीयकरण के उद्देश्यों के लिए भी उपयोगी नहीं है क्योंकि अंग्रेजी तार और प्रोग्राम में नामों के बीच मानचित्रण अब नकल से बचने के आपके प्रयास से कठिन-कोडित है। कम से कम अन्य तरीकों के साथ, स्रोत फ़ाइलों में प्रत्येक घटना को बदले बिना तारों का अनुवाद करना संभव है।
R .. गिटहब स्टॉप हेल्पिंग ICE

1
आप शायद इसे (गेटटेक्स्ट जैसी चीज़ के साथ) रिटर्न स्टेटमेंट को बदलकर इसे return _(#element)और इस तरह से अंतर्राष्ट्रीयकृत कर सकते हैं।
वर्गास

जब सी प्रीप्रोसेसर यह उपयोगी है लेकिन यह बदसूरत है, तो मैं आमतौर पर इसे एक स्क्रिप्टिंग भाषा में एक साधारण कोड जनरेटर या कस्टम प्रीप्रोसेसर के साथ बदल देता हूं। और वास्तव में, मुझे एक पायथन स्क्रिप्ट मिली है जिसका उपयोग मैंने कई परियोजनाओं में इस उद्देश्य के लिए किया है। लेकिन मैं इसका उपयोग आजकल नहीं करता हूं- कई उपयोग के मामलों के लिए, आप केवल तारों का उपयोग करके दूर हो सकते हैं और एनम के साथ परेशान नहीं कर सकते (और यहां तक ​​कि C ++ या ObjC में भी)।
अचानक

6

जिस तरह से मैं आमतौर पर ऐसा करता हूं उसी क्रम में एक अलग सरणी में स्ट्रिंग अभ्यावेदन का भंडारण करके, फिर एनून मान के साथ सरणी को अनुक्रमित करना:

const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"

4

enumसी में वास्तव में जिस तरह से आप उनसे उम्मीद कर रहे हैं वह काम नहीं करते हैं। आप उनकी तरह गौरवशाली स्थिरांक के बारे में सोच सकते हैं (कुछ अतिरिक्त लाभ होने के साथ संबंधित होने के नाते एक संग्रह ऐसे स्थिरांक का ), और आपके द्वारा "रविवार" के लिए लिखे गए पाठ वास्तव में संकलन के दौरान एक नंबर पर हल हो जाते हैं, पाठ है अंततः त्याग दिया।

संक्षेप में: ऐसा करने के लिए जिसे आप वास्तव में चाहते हैं, आपको तार की एक सरणी रखने की आवश्यकता होगी या एनुम के मूल्य से उस पाठ तक मानचित्र बनाने के लिए एक फ़ंक्शन बनाएं जिसे आप प्रिंट करना चाहते हैं।


4

सी में गणना स्वचालित रूप से अनुक्रमित पूर्णांक मानों की सूची के लिए मूल रूप से वाक्य रचना चीनी है। जब आपके पास यह कोड है:

int main()
{
    enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

    Days TheDay = Monday;
}

आपका संकलक वास्तव में इसे बाहर निकालता है:

int main()
{
    int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}

इसलिए, स्ट्रिंग के रूप में सी एन्यूमरेशन को आउटपुट करना एक ऑपरेशन नहीं है जो कंपाइलर के लिए समझ में आता है। यदि आप इनके लिए मानव-पठनीय तार चाहते हैं, तो आपको गणनाओं से तार में बदलने के लिए कार्यों को परिभाषित करना होगा।


4

मैक्रोज़ के साथ इसे करने का एक साफ़ तरीका है:

#include <stdio.h>
#include <stdlib.h>

#define DOW(X, S)                                                         \
    X(Sunday) S X(Monday) S X(Tuesday) S X(Wednesday) S X(Thursday) S X(Friday) S X(Saturday)

#define COMMA ,

/* declare the enum */
#define DOW_ENUM(DOW) DOW
enum dow {
    DOW(DOW_ENUM, COMMA)
};

/* create an array of strings with the enum names... */
#define DOW_ARR(DOW ) [DOW] = #DOW
const char * const dow_str[] = {
    DOW(DOW_ARR, COMMA)
};

/* ...or create a switchy function. */
static const char * dowstr(int i)
{
#define DOW_CASE(D) case D: return #D

    switch(i) {
        DOW(DOW_CASE, ;);
    default: return NULL;
    }
}


int main(void)
{
    for(int i = 0; i < 7; i++)
        printf("[%d] = «%s»\n", i, dow_str[i]);
    printf("\n");
    for(int i = 0; i < 7; i++)
        printf("[%d] = «%s»\n", i, dowstr(i));
    return 0;
}

मुझे यकीन नहीं है कि यह पूरी तरह से पोर्टेबल बी / डब्ल्यू प्रीप्रोसेसर है, लेकिन यह जीसीसी के साथ काम करता है।

यह c99 btw है, इसलिए c99 strictयदि आप इसे (ऑनलाइन कंपाइलर) विचारधारा में प्लग करते हैं तो उपयोग करें ।


होगा प्यार कैसे "साफ" मैक्रो :-) हैं।
mk12 18

3

मुझे पता है कि मुझे पार्टी में देर हो रही है, लेकिन इस बारे में कैसे?

const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ };
printf("%s", dayNames[Sunday]); // prints "Sunday"

इस तरह, आपको मैन्युअल रूप से enumऔर char*सरणी को सिंक में रखने की आवश्यकता नहीं है। यदि आप मेरी तरह हैं, तो संभावना है कि आप बाद में बदल देंगे enum, और char*सरणी अमान्य स्ट्रिंग्स को प्रिंट करेगी। यह सार्वभौमिक रूप से समर्थित सुविधा नहीं हो सकती है। लेकिन afaik, अधिकांश मॉडर्न डे C कंपाइलर इस नामित शुरुआती शैली का समर्थन करते हैं।

आप यहां नामित शुरुआती के बारे में अधिक पढ़ सकते हैं ।


1

सवाल यह है कि आप केवल एक बार नाम लिखना चाहते हैं।
मेरे पास इस तरह एक आईडी है:

#define __ENUM(situation,num) \
    int situation = num;        const char * __##situation##_name = #situation;

    const struct {
        __ENUM(get_other_string, -203);//using a __ENUM Mirco make it ease to write, 
        __ENUM(get_negative_to_unsigned, -204);
        __ENUM(overflow,-205);
//The following two line showing the expanding for __ENUM
        int get_no_num = -201;      const char * __get_no_num_name = "get_no_num";
        int get_float_to_int = -202;        const char * get_float_to_int_name = "float_to_int_name";

    }eRevJson;
#undef __ENUM
    struct sIntCharPtr { int value; const char * p_name; };
//This function transform it to string.
    inline const char * enumRevJsonGetString(int num) {
        sIntCharPtr * ptr = (sIntCharPtr *)(&eRevJson);
        for (int i = 0;i < sizeof(eRevJson) / sizeof(sIntCharPtr);i++) {
            if (ptr[i].value == num) {
                return ptr[i].p_name;
            }
        }
        return "bad_enum_value";
    }

यह एनम सम्मिलित करने के लिए एक संरचना का उपयोग करता है, ताकि एक प्रिंटर स्ट्रिंग के लिए प्रत्येक एनम मान को परिभाषित कर सके।

int main(int argc, char *argv[]) {  
    int enum_test = eRevJson.get_other_string;
    printf("error is %s, number is %d\n", enumRevJsonGetString(enum_test), enum_test);

>error is get_other_string, number is -203

यदि संख्या दोहराई जाती है, तो एनम का अंतर बिल्डर को रिपोर्ट नहीं कर सकता है। यदि आपको नंबर लिखना पसंद नहीं है, तो __LINE__इसे बदल सकते हैं:

#define ____LINE__ __LINE__
#define __ENUM(situation) \
    int situation = (____LINE__ - __BASELINE -2);       const char * __##situation##_name = #situation;
constexpr int __BASELINE = __LINE__;
constexpr struct {
    __ENUM(Sunday);
    __ENUM(Monday);
    __ENUM(Tuesday);
    __ENUM(Wednesday);
    __ENUM(Thursday);
    __ENUM(Friday);
    __ENUM(Saturday);
}eDays;
#undef __ENUM
inline const char * enumDaysGetString(int num) {
    sIntCharPtr * ptr = (sIntCharPtr *)(&eDays);
    for (int i = 0;i < sizeof(eDays) / sizeof(sIntCharPtr);i++) {
        if (ptr[i].value == num) {
            return ptr[i].p_name;
        }
    }
    return "bad_enum_value";
}
int main(int argc, char *argv[]) {  
    int d = eDays.Wednesday;
    printf("day %s, number is %d\n", enumDaysGetString(d), d);
    d = 1;
    printf("day %s, number is %d\n", enumDaysGetString(d), d);
}

>day Wednesday, number is 3 >day Monday, number is 1


0

मैं इस के लिए नया हूँ, लेकिन एक स्विच स्टेटमेंट बहुत काम करेगा

#include <stdio.h>

enum mycolor;

int main(int argc, const char * argv[])

{
enum Days{Sunday=1,Monday=2,Tuesday=3,Wednesday=4,Thursday=5,Friday=6,Saturday=7};

enum Days TheDay;


printf("Please enter the day of the week (0 to 6)\n");

scanf("%d",&TheDay);

switch (TheDay)
 {

case Sunday:
        printf("the selected day is sunday");
        break;
    case Monday:
        printf("the selected day is monday");
        break;
    case Tuesday:
        printf("the selected day is Tuesday");
        break;
    case Wednesday:
        printf("the selected day is Wednesday");
        break;
    case Thursday:
        printf("the selected day is thursday");
        break;
    case Friday:
        printf("the selected day is friday");
        break;
    case Saturday:
        printf("the selected day is Saturaday");
        break;
    default:
        break;
}

return 0;
}

उचित प्रारूपण (पढ़ें: इंडेंटेशन) उत्तर में शब्दशः कोड के लिए होना चाहिए ...
p4010 12

0

मुझे यह पसंद है कि दिन में नाम रखें। टाइपिंग को कम करने के लिए, हम निम्न कार्य कर सकते हैं:

#define EP(x) [x] = #x  /* ENUM PRINT */

const char* dayNames[] = { EP(Sunday), EP(Monday)};

0

एक और उपाय है: अपनी खुद की गतिशील गणना कक्षा बनाएं। इसका मतलब है कि आपके पास एक structनया गणन बनाने के लिए एक और कुछ फ़ंक्शन है, जो तत्वों को एक में संग्रहीत करता है structऔर प्रत्येक तत्व में नाम के लिए एक स्ट्रिंग है। आपको व्यक्तिगत तत्वों को संग्रहीत करने के लिए कुछ प्रकार की आवश्यकता होती है, उनकी तुलना करने के लिए फ़ंक्शन और इतने पर। यहाँ एक उदाहरण है:

#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


struct Enumeration_element_T
{
  size_t index;
  struct Enumeration_T *parrent;
  char *name;
};

struct Enumeration_T
{
  size_t len;
  struct Enumeration_element_T elements[];
};
  


void enumeration_delete(struct Enumeration_T *self)
{
  if(self)
  {
    while(self->len--)
    {
      free(self->elements[self->len].name);
    }
    free(self);
  }
}

struct Enumeration_T *enumeration_create(size_t len,...)
{
  //We do not check for size_t overflows, but we should.
  struct Enumeration_T *self=malloc(sizeof(self)+sizeof(self->elements[0])*len);
  if(!self)
  {
    return NULL;
  }
  self->len=0;
  va_list l; 
  va_start(l,len);
  for(size_t i=0;i<len;i++)
  {
    const char *name=va_arg(l,const char *);
    self->elements[i].name=malloc(strlen(name)+1);
    if(!self->elements[i].name)
    {
      enumeration_delete(self);
      return NULL;
    }
    strcpy(self->elements[i].name,name);
    self->len++;
  }
  return self;
}


bool enumeration_isEqual(struct Enumeration_element_T *a,struct Enumeration_element_T *b)
{
  return a->parrent==b->parrent && a->index==b->index;
}

bool enumeration_isName(struct Enumeration_element_T *a, const char *name)
{
  return !strcmp(a->name,name);
}

const char *enumeration_getName(struct Enumeration_element_T *a)
{
  return a->name;
}

struct Enumeration_element_T *enumeration_getFromName(struct Enumeration_T *self, const char *name)
{
  for(size_t i=0;i<self->len;i++)
  {
    if(enumeration_isName(&self->elements[i],name))
    {
      return &self->elements[i];
    }
  }
  return NULL;
}
  
struct Enumeration_element_T *enumeration_get(struct Enumeration_T *self, size_t index)
{
  return &self->elements[index];
}

size_t enumeration_getCount(struct Enumeration_T *self)
{
  return self->len;
}

bool enumeration_isInRange(struct Enumeration_T *self, size_t index)
{
  return index<self->len;
}



int main(void)
{
  struct Enumeration_T *weekdays=enumeration_create(7,"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
  if(!weekdays)
  {
    return 1;
  }
    
  printf("Please enter the day of the week (0 to 6)\n");
  size_t j = 0;
  if(scanf("%zu",&j)!=1)
  {
    enumeration_delete(weekdays);
    return 1;
  }
  // j=j%enumeration_getCount(weekdays); //alternative way to make sure j is in range
  if(!enumeration_isInRange(weekdays,j))
  {
    enumeration_delete(weekdays);
    return 1;
  }

  struct Enumeration_element_T *day=enumeration_get(weekdays,j);
  

  printf("%s\n",enumeration_getName(day));
  
  enumeration_delete(weekdays);

  return 0;
}

गणना का कार्य अपनी स्वयं की अनुवाद इकाई में होना चाहिए, लेकिन मैंने इसे सरल बनाने के लिए यहां संयोजित किया।

लाभ यह है कि यह समाधान लचीला है, DRY सिद्धांत का अनुसरण करता है, आप प्रत्येक तत्व के साथ जानकारी संग्रहीत कर सकते हैं, आप रनटाइम के दौरान नई गणना बना सकते हैं और रनटाइम के दौरान नए तत्व जोड़ सकते हैं। नुकसान यह है कि यह जटिल है, गतिशील मेमोरी आवंटन की आवश्यकता है, इसमें उपयोग नहीं किया जा सकता है switch- caseअधिक मेमोरी की आवश्यकता है और धीमी है। सवाल यह है कि क्या आपको उन मामलों में उच्च स्तर की भाषा का उपयोग नहीं करना चाहिए जहां आपको इसकी आवश्यकता है।


-3

TheDay कुछ पूर्णांक प्रकार पर वापस मैप करता है। इसलिए:

printf("%s", TheDay);

TheDay को एक स्ट्रिंग के रूप में पार्स करने का प्रयास, और या तो कचरा या दुर्घटना का प्रिंट आउट लेगा।

प्रिंटफ टाइपसेफ नहीं है और आपको इस पर सही मूल्य देने के लिए भरोसा है। मूल्य का नाम प्रिंट करने के लिए, आपको एनम वैल्यू को स्ट्रिंग में मैप करने के लिए कुछ विधि बनाने की आवश्यकता होगी - या तो एक लुकअप टेबल, विशाल स्विच स्टेटमेंट, आदि।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.