For VC++, here's the test about forward declaration and specifying the underlying type:
- The following code is compiled OK.
    typedef int myint;
    enum T ;
    void foo(T * tp )
    {
        * tp = (T)0x12345678;
    }
    enum T : char
    {
        A
    };
But I got the warning for /W4 (/W3 does not incur this warning)
warning C4480: nonstandard extension used: specifying underlying type for enum 'T'
- VC++ (Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86) looks buggy in the above case:
- when seeing enum T; VC assumes the enum type T uses default 4 bytes int as underlying type, so the generated assembly code is:
    ?foo@@YAXPAW4T@@@Z PROC                    ; foo
    ; File e:\work\c_cpp\cpp_snippet.cpp
    ; Line 13
        push    ebp
        mov    ebp, esp
    ; Line 14
        mov    eax, DWORD PTR _tp$[ebp]
        mov    DWORD PTR [eax], 305419896        ; 12345678H
    ; Line 15
        pop    ebp
        ret    0
    ?foo@@YAXPAW4T@@@Z ENDP                    ; foo
The above assembly code is extracted from /Fatest.asm directly, not my personal guess.
Do you see the
mov DWORD PTR[eax], 305419896        ; 12345678H
line?
the following code snippet proves it:
    int main(int argc, char *argv)
    {
        union {
            char ca[4];
            T t;
        }a;
        a.ca[0] = a.ca[1] = a.[ca[2] = a.ca[3] = 1;
        foo( &a.t) ;
        printf("%#x, %#x, %#x, %#x\n",  a.ca[0], a.ca[1], a.ca[2], a.ca[3] );
        return 0;
    }
The result is:
0x78, 0x56, 0x34, 0x12
- After removing the forward declaration of enum T and move the definition of function foo after the enum T's definition: the result is OK:
The above key instruction becomes:
mov    BYTE PTR [eax], 120            ; 00000078H
The final result is:
0x78, 0x1, 0x1, 0x1
Note the value is not being overwritten.
So using of the forward-declaration of enum in VC++ is considered harmful.
BTW, to not surprise, the syntax for declaration of the underlying type is same as its in C#. In pratice I found it's worth to save three bytes by specifying the underlying type as char when talking to the embedded system, which is memory limited.