Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie
Hi there,
There is an issue with role permissions that is being worked on at the moment.
If you are having trouble with access or permissions on regional forums please post here to get access: https://www.boards.ie/discussion/2058365403/you-do-not-have-permission-for-that#latest

Accessing enumerations by name and by value (C Language)

  • 31-12-2015 1:50am
    #1
    Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭


    Hi,

    If I created an enumerated type in C - say days of week - am I able to reference any enumeration within that type by either its name (e.g. "Monday", "Saturday", ... etc.) and by a numerical represenation (e.g. Mon = 0, Tues = 1, Wed = 2, ...etc.).

    In some other languages I've used, it was possible to overlay an alias onto the address of the variable and read out the enumeration literal assigned to it as an integer value.

    How does the C compilers store enumerations? Does it vary depending on the compiler used?


    Also, if it is possible, can I modify the type definition to start Monday = 1, Tuesday = 2, ... etc.

    Thanks.


Comments

  • Registered Users, Registered Users 2 Posts: 768 ✭✭✭14ned


    Hi,

    If I created an enumerated type in C - say days of week - am I able to reference any enumeration within that type by either its name (e.g. "Monday", "Saturday", ... etc.) and by a numerical represenation (e.g. Mon = 0, Tues = 1, Wed = 2, ...etc.).

    For C style enums, the enum will implicitly convert to int on demand. You have to cast to send it the other way though.

    For C++11 style enums, you must always cast between the enum type and its underlying type (which could be an int, float, or any constexpr type).
    In some other languages I've used, it was possible to overlay an alias onto the address of the variable and read out the enumeration literal assigned to it as an integer value.

    How does the C compilers store enumerations? Does it vary depending on the compiler used?

    enums exist purely within the C and C++ type system. They have no representation in the code generated.

    All C and C++ compilers start enums at 0 unless told otherwise, so the first item is always 0, the next item is always 1, the next 2 and so on.
    Also, if it is possible, can I modify the type definition to start Monday = 1, Tuesday = 2, ... etc.

    Thanks.

    Of course. Simply assign any value you want. Be aware non-contiguous values may produce sub-optimal code though.

    Niall


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    I'm trying to convert an Integer into a String. However, I've mucked up somewhere and can't figure out what I've done wrong.

    Yes - I realise that I can just return the RHS of the statement instead of assigning a variable as an intermediate point. I had it in place for debug reasons.
    char Convert(int day){
      
       // Text held within an array
       const char *dayArray[] = {"Text1", "Text2", "Text3", "Text4", "Text5"};
    
       char dayString = dayArray[(char)day];       
    
       return dayString; 
    
    ...
        // Debug data
        char firstday = Convert(initialDayInt);
        char finalday = Convert(dayCount);
    
    ...
        printf("Initial Day: %c\n", firstday);
        printf("Final Day: %c\n", finalday); 
    }
    

    The output from the above (no compilation errors or warnings):
    printf("Initial Day: %c\n", firstday);
        printf("Final Day: %c\n", finalday);
    

    I'm also wondering if it would be more efficient to use a switch statement instead of the above. Would this be so?

    Alternatively, should I be looking to create dayString to be of enumerate type daysOfWeek and then cast the int day onto dayString? If so, how is this done?

    My debug is showing that I'm not getting the dayString variable populated correctly.


    Thanks.


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    Okay, I've realised that I need to use %s instead of %c. However, I'm still struggling to get it to work.


  • Registered Users, Registered Users 2 Posts: 768 ✭✭✭14ned


    I'm trying to convert an Integer into a String. However, I've mucked up somewhere and can't figure out what I've done wrong.

    Yes - I realise that I can just return the RHS of the statement instead of assigning a variable as an intermediate point. I had it in place for debug reasons.
    char Convert(int day){
      
       // Text held within an array
       const char *dayArray[] = {"Text1", "Text2", "Text3", "Text4", "Text5"};
    
       char dayString = dayArray[(char)day];       
    
       return dayString; 
    
    ...
        // Debug data
        char firstday = Convert(initialDayInt);
        char finalday = Convert(dayCount);
    
    ...
        printf("Initial Day: %c\n", firstday);
        printf("Final Day: %c\n", finalday); 
    }
    

    The output from the above (no compilation errors or warnings):
    printf("Initial Day: %c\n", firstday);
        printf("Final Day: %c\n", finalday);
    

    Hmm, smells like a homework assignment! Luckily I'm on christmas vacation!

    Firstly, don't use char * for strings in C++. Use std::string. If you really, really, really must use char *, then use std::experimental::string_view instead (http://en.cppreference.com/w/cpp/header/experimental/string_view).

    The code you posted above may have been mispasted. You are returning a single char, not a pointer to an array of char.

    Also never index arrays using char which is an enormous security hole and highly prone to corrupting memory. Only ever use size_t to index arrays.

    Finally never do unchecked array lookup. Always check if the index being looked up exceeds the array length, otherwise it's another security hole and and memory corruption possibility.
    I'm also wondering if it would be more efficient to use a switch statement instead of the above. Would this be so?

    No. In modern C++ there is very little correlation between the code you type and what code is generated. This is why it takes at least 10,000 hours to master C++ to learn the typical transformation patterns used by the big three compilers, and the approx. 10-15% pay bump experienced C++ engineers see over Java ones.

    Modern C++ compilers optimise using topological transforms, so imagine a bendy sheet which must be tamped down between partially moveable sharp points and it's a good analogy.
    Alternatively, should I be looking to create dayString to be of enumerate type daysOfWeek and then cast the int day onto dayString? If so, how is this done?

    My debug is showing that I'm not getting the dayString variable populated correctly.


    Thanks.

    It seems awfully like you need to choose one of the many solutions from https://stackoverflow.com/questions/207976/how-to-easily-map-c-enums-to-strings. https://stackoverflow.com/questions/201593/is-there-a-simple-way-to-convert-c-enum-to-string#201792 is also worth reading for a preprocessor method of auto generating strings from enums.

    I remember someone proposing a Boost library (http://www.boost.org/) for this stuff, but I don't think it got submitted for peer review.

    Niall


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    No - not homework. Unemployed and retraining.

    Also, I'm doing the above in C, not C++. Does this affect your reply?


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    14ned wrote: »
    Hmm, smells like a homework assignment! Luckily I'm on christmas vacation!
    Got made redundant beforce Christmas, so I'm trying to gain some additional skills to broaden my CV.
    The code you posted above may have been mispasted. You are returning a single char, not a pointer to an array of char.
    Yes, I noticed this when doing some further debugging. I can read the array value directly (e.g. dayArray[2]) but not indirectly using the variable.


  • Registered Users, Registered Users 2 Posts: 768 ✭✭✭14ned


    Got made redundant beforce Christmas, so I'm trying to gain some additional skills to broaden my CV.

    Good on you for reacting this way. Whenever I'm between contracts I always take a course, I've got most of the way through an OU Maths degree doing that now which will be my third undergrad degree. Still, it's never easy getting laid off, whatever the circumstances.
    Yes, I noticed this when doing some further debugging. I can read the array value directly (e.g. dayArray[2]) but not indirectly using the variable.

    As you're writing all this in C not C++, you're kinda stuck with zero terminated char arrays as the string representation unless you bring in a third party library which in any production code you always would, because C strings are utterly evil and riddled with traps. The biggest lesson I have learned from twenty years plus of writing C is don't write in C :)

    Anyway, warnings aside, your string array looks like this:
    static const char *weekdays[]={"Monday", "Tuesday", ... };
    

    The type of weekdays is const char *[7] which will decay on demand to const char **, so a pointer to a pointer to a const char. When you index weekdays like this:
    const char *tuesday=weekdays[1];
    

    The type of tuesday is now a pointer to a const char. Indexing that again:
    const char u=tuesday[1];
    

    Printing these would be as follows:
    printf("%c\n", u); // prints u
    printf("%s\n", tuesday); // prints Tuesday
    for(size_t n=0; n<sizeof(weekdays)/sizeof(*weekdays); n++)
      printf("%u: %s\n", (unsigned) n, weekdays[n]);
    // prints 0: Monday, 1: Tuesday, 2: Wednesday etc.
    

    I suspect your difficulty would be greatly helped if you enable all warnings, so if on GCC or clang use /Wall. If on MSVC make warnings Level 4 and enable Code Analysis.

    Also if on MSVC, absolutely use VS2015 with Update 1 applied and forget about all earlier MSVC's. VS2015 is a quantum leap forward for Microsoft's compiler, it finally even has most of C99 support only fifteen years late!

    Finally, if all the above looks greek to you, I'd suggest taking an online marked course in the C or C++ type system. I've been told they exist and some are quite good, but I know of none myself.

    Niall


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    Thanks - I've got it working now in the funtion. I now have:
    const char Convert(int day){
      
       // Text held within an array
       const char *dayArray[] = {"Text1", "Text2", "Text3", "Text4", "Text5"};
    
       char *dayString = dayArray[day];       
    
       return *dayString; 
    
    ...
        // Debug data
        const char *firstday = Convert(initialDayInt);
        const char *finalday = Convert(dayCount);
    
    ...
        printf("Initial Day: %s\n", *firstday);
        printf("Final Day: %s\n", *finalday); 
    }
    

    However, I can't get the first day and final day to print out. I'm still not 100% comfortable with my understanding of these pointers.

    I can, however get the first character of the text to output correctly though:
    // Debug data
        const char firstday = Convert(initialDayInt);
        const char finalday = Convert(dayCount);
    
    ...
        printf("Initial Day: %c\n", firstday);
        printf("Final Day: %c\n", finalday); 
    }
    

    Help? I just can't visualise what is (and what should be) happenng when I'm trying to use strings.


  • Registered Users, Registered Users 2 Posts: 768 ✭✭✭14ned


    Thanks - I've got it working now in the funtion. I now have:
    const char Convert(int day){
      
       // Text held within an array
       const char *dayArray[] = {"Text1", "Text2", "Text3", "Text4", "Text5"};
    
       char *dayString = dayArray[day];       
    
       return *dayString; 
    
    ...
        // Debug data
        const char *firstday = Convert(initialDayInt);
        const char *finalday = Convert(dayCount);
    
    ...
        printf("Initial Day: %s\n", *firstday);
        printf("Final Day: %s\n", *finalday); 
    }
    

    However, I can't get the first day and final day to print out. I'm still not 100% comfortable with my understanding of these pointers.

    I can, however get the first character of the text to output correctly though:
    // Debug data
        const char firstday = Convert(initialDayInt);
        const char finalday = Convert(dayCount);
    
    ...
        printf("Initial Day: %c\n", firstday);
        printf("Final Day: %c\n", finalday); 
    }
    

    Help? I just can't visualise what is (and what should be) happenng when I'm trying to use strings.

    Convert() should definitely be returning a const char *. Use %s to print a const char * as a string.

    Niall


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    14ned wrote: »
    Convert() should definitely be returning a const char *. Use %s to print a const char * as a string.

    Niall

    Hi Niall, thanks for your reply - is that not what I'm doing here:
    ...     
    // Debug data     
    const char *firstday = Convert(initialDayInt);     
    const char *finalday = Convert(dayCount);  
    ...     
    printf("Initial Day: %s\n", *firstday);     
    printf("Final Day: %s\n", *finalday);  }
    
    I've also tried it with the printf statements modified as:
    printf("Initial Day: %s\n", firstday);     
    printf("Final Day: %s\n", finalday);  }
    
    I get the following errors:
    main.c:151:28: warning: initialization makes pointer from integer without a cast
         const char *firstday = ConvertDayToString(initialDayInt);
                                ^
    main.c:152:28: warning: initialization makes pointer from integer without a cast
         const char *finalday = ConvertDayToString(dayCount);
                                ^
    
    BTW - I'm using NetBeans 8.1 as my IDE.

    Also, why did you prefix the dayArray declaration with 'static'?


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 768 ✭✭✭14ned


    Hi Niall, thanks for your reply - is that not what I'm doing here:

    Nope:
    const char Convert(int day){
    

    should be:
    const char *Convert(int day){
    
    I get the following errors:
    main.c:151:28: warning: initialization makes pointer from integer without a cast
         const char *firstday = ConvertDayToString(initialDayInt);
                                ^
    main.c:152:28: warning: initialization makes pointer from integer without a cast
         const char *finalday = ConvertDayToString(dayCount);
                                ^
    
    BTW - I'm using NetBeans 8.1 as my IDE.

    Yep you are doing an implicit conversion from a char to an int, and using that to initialise a pointer. Very bad.

    I would keep changing the code until you see no more warnings anyway, that's for sure.
    Also, why did you prefix the dayArray declaration with 'static'?

    If you don't, it gets auto duration which means the compiler will make a copy of the array every time you execute Convert(). If it has static duration, it doesn't copy the array.

    Niall


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    Can you explain to me why the * is needed prior to the name of the Convert function.

    Is it normal to have * beside every IO parameter in the function declaration?

    The structure I was following has char * prefix on them but I was trying to pass in an attribute of the month array which is a constant char *.
    This was giving me a compiler warning which I avoided by prefixing the function declarations with const.

    Thanks.


  • Registered Users, Registered Users 2 Posts: 768 ✭✭✭14ned


    Can you explain to me why the * is needed prior to the name of the Convert function.

    You are returning a pointer to a char, not a char itself.

    Remember, strings in C are simply arrays of char. C does not allow variable length arrays to be returned from functions, so the next best thing to do is to return a pointer to the first item in the array.
    Is it normal to have * beside every IO parameter in the function declaration?

    Only if the parameter being passed is a pointer to something rather than a something.

    You can also have a pointer to a pointer to something e.g. int **foo;

    A pointer to a pointer to a pointer to something also works e.g. float ***foo;

    The star isn't a prefix, it is part of the type, same as any const-ness.

    Niall


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    Thanks, so it is normal when creating a function to pass the parameters using pointers?


  • Registered Users, Registered Users 2 Posts: 768 ✭✭✭14ned


    Thanks, so it is normal when creating a function to pass the parameters using pointers?

    It depends. If you passed the entire array as a parameter, the compiler would copy the entire array every time you enter the function. Similarly if you return an entire array, the compiler will again copy the whole thing on exit.

    If you pass a pointer to something, it simply copies the pointer instead.

    C is barely above Assembler i.e. it is very stupid. It does exactly what you tell it to do, provides no safety, no hand holding and no helpful behaviours like other languages. Unless you have a very good reason to program in C or C++, choose anything else like Java or Python or C# or Swift or Rust all of which are better choices almost all of the time.

    Experienced C++ programmers earn 10-25% more than experienced devs in other languages because it takes at least five, and more usually ten, years of experience to master the complexity that is modern C++ - even those on the ISO C++ standard committee say none of them really understands the language even though they as a collective designed the thing. Even C will take you two or three years of daily use before you are competent, and that is assuming you attend week long training conferences three times a year each costing a thousand euro at least.

    I'd urge you down any other path than C or C++ unless you are willing to invest years of your life training yourself up. Most of the big software bugs which wreck lives were written by incompetent C programmers, so most employers now expect a very high standard and are unwilling to train up junior programmers in C.

    Niall


  • Registered Users, Registered Users 2 Posts: 8,593 ✭✭✭funkey_monkey


    Thanks for that. I'm applying for a few jobs and trying to avoid anything with C. But still I want to have an initial grip of it. I need to sort myself out with pointers. I undertand them in principal, but in practice, it is causing problems.

    Got some good feedback about a job in Java - a language I used a number of years ago. Been using proprietary languages for a number of years now.

    Related to pointers, are you able to help with the PM I sent you?


    Thanks for your replies.


Advertisement