Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 2 of 2

Thread: Converting code to C/C++ for use on the teensy 4.X (Enums in C)

  1. #1
    Junior Member
    Join Date
    Nov 2020
    Location
    Montana, USA
    Posts
    15

    Converting code to C/C++ for use on the teensy 4.X (Enums in C)

    Back in 2015 I posted code on the Parallax Forums that I wrote to emulate a few logic chips (link: https://forums.parallax.com/discussi...logic-emulator ) in Spin languange for the P8X32A Propeller Microcontroller.

    I would like to convert it to C/C++ for use on teensy 4.X, I've searched and have gotten myself a bit confused as what would be the correct, or recomended. I see an enum can be declared a few different ways, here are the methods used to declare enums I see through the plethora of available code in search results:

    1.) Name of enum after coder
    Code:
    enum{
        choice-01,
        choice-02,
        choice-03
    } someEnum;
    2.) name of enum before code
    Code:
    enum someEnum{
        choice-01,
        choice-02,
        choice-03
    };
    3.) name of enum both before and after with differnent casing
    Code:
    enum someEnum{
        choice-01,
        choice-02,
        choice-03
    } SomeEnum;
    4,5,6.) same as the three above but with "typedef enum...".

    So... which one is prefered common practice, does it matter? Is one method for C and the other for C++?

    Thank you in advance.

  2. #2
    Senior Member
    Join Date
    Feb 2015
    Location
    Finland
    Posts
    239
    First, a dash or minus (-) is not a valid character in C identifiers; you should use for example underscore (_) instead. Basically, it's easiest to just limit oneself to letters A-Z and a-z (case sensitive), digits 0-9 (but not as the first character), and underscore _.

    Arduino/Teensyduino uses C++ rules (as opposed to C rules), except within a extern "C" { ... } block (in the ... part), which uses C rules overall.

    There are two basic patterns common to both:
        enum enumtypename { list... } variablename ;
        typedef enum enumtypename { list... } typename ;
    where enumtypename is optional. If variablename is used, it declares a variable of that enum type.
    The list... is a comma-separated list of names, where any name can be appended with the specific integer value (say, = 5) for that one. The following ones without a specific integer value will get incremental values.

    In C, enums are just ints, and the standard/recommended form is just
        enum { list... };
    This also works in C++, and is called unscoped enumeration. The names in list... are often written in all UPPERCASE, similar to preprocessor macros. Anywhere an int is used, you can use any of the names listed in any of the list...'s. In this case, it is best to prefix each name with the facility (for example your library name), and an underscore, so that such unscoped enumerations from different libraries won't clash. (Say, OLED_, GFX_, and so on.)

    In C++, you can also specify the underlying type, you're not limited to int. See here for a quick tutorial. I would recommend form
        enum typename:basetype { list... };
    Then, when given a variable of type typename or basetype, you can use any of the names in list... to describe the actual values, including in arithmetic. Variables of type typename are treated as basetype by the compiler.

    I personally like to use the exact-width or fast integer types for basetype: uintN_t or intN_t for exact-width types especially when used in data structures, and uint_fastN_t or int_fastN_t fast variants for use in function calls. Here, N is 8, 16, 32, or 64.

    The fast variants are useful when the enumerations are used mostly in function calls, because the compiler will pick the most efficient storage size for the type at compile time. For example, on 32-bit ARMs like Teensy LC, 3.x, 4.x, uint_fastN_t and int_fastN_t are actually uint32_t and int32_t for N=8, 16, and 32, because these Teensies use 32-bit ARM Cortex microcontrollers that are most efficient when working on 32-bit units. (The same applies to desktop programming, too. On x86 and x86-64, the 8-bit fast types are 8-bit, and 16-bit ones are usually 32-bit, but it varies slightly between operating systems because they can use different conventions on argument passing in function calls, "function call ABI", on the same hardware. The 32-bit Teensies use "arm-none-eabi".)

    If your data structures are only used in your firmware, and you're not tight on RAM, then it is okay to use the fast types in data structures and variables also; I most definitely do. It's only when the data structures are e.g. passed to/from the computer, or you're tight on RAM, that using specific-size types makes interoperability easier, and data structures have specific, easily controlled sizes.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •