Fourcc's generation
What is Fourcc?
Fourcc is a full name Four-Character Codes, which is very common in programming, generally used as a marker. For example, the label header of the RIFF file such as WAV, AVI, the model file of Quake 3. MD3 is also a large amount of Fourcc equals "IDP3". It is a 32-bit marker, in fact,
Typedef unsigned long fourcc
Macro into Fourcc
Fourcc is spliced by four characters. The traditional way to generate a Fourcc is:
// from MMSystem.h
#define makefourcc (CH0, CH1, CH2, CH3) /
((DWORD) (CHTE) | ((DWORD) (Byte) (CH1) << 8) | /
((DWORD) (CHTE) << 16) | (DWORD) (BYTE) (CH3) << 24))
This method is simple and intuitive, and the following code:
Switch (VAL)
{
Case makefourcc ('f', 'm', 't', '):
...
Break;
Case makefourcc ('d', 'a', 't', 'a'):
...
Break;
...
}
It can be compiled smoothly because the macro can generate constants in the compile period, which conforms to Case conditions.
Inline function?
If you are a pure C user, you will be very disgusted with the macro with parameters, whether it is "The C Programming Language", "Effective C " or other good C books, will persuade you don't use the parameters It will also list a lot of examples, and the harm of macro. Thinking of this, you will feel that you should use the inline function to replace the macro with parameters. So you wrote the following code:
Inline Fourcc Makefourcc (Char CH0, CHAR CH1, CHAR CH2, CHAR CH3)
{
Return (CH0 << 0) (CH1 << 8) (CH2 << 16) (CH3 << 24);
}
OK, it has achieved the act of the original macro and can get the correct result. You may think this is the perfect answer. Slow, when you join the new code to the project, then you will find that the compilation failed! Case the line error. This is because the value behind CAS must be constant. So you modified the code:
Const Fourcc Fccfmt = Makefourcc ('f', 'm', 't', ');
Const Fourcc Fccdata = Makefourcc ('D', 'A', 'T', 'A');
...
Switch (VAL)
{
Case FCCFMT:
...
Break;
Case Fccdata:
...
Break;
...
}
You attempted to store the calculation results in FCCFMT and FCCData by defining the constant constant. However, the error is old. "But all the four parameters I brought by Makefourcc are constants? You should calculate the return value of Makefourcc when compiling!" I heard you shouting loudly. Indeed, at the optimization phase, Makefourcc can calculate the results and stored in constant FCCFMT and FCCDATA and may be directly brought into their values directly using FCCFMT and FCCDATA. However, please note that compile is before optimization, that is, the value behind Case must be a specific value in the compilation phase, and cannot wait until the optimization phase. Moreover, the Debug version defaults to no optimization without inline, so the program is also denied. More to explain, the "inline" keyword is just a suggestion, not a command. It can only recommend compilers: "If allowable, please use it in line." And the compiler completely relies on the inline function. Therefore, the inline function is no longer compiled. Use template!
Do you want to return an old macro? Of course, it is not, what else should be done :) C template mechanism gives the programmer's unlimited space, it is not only possible to make the type as a parameter, and constant can be used as a parameter (this is often forgotten), and All this is determined by the compile period! This is the first foundation we use to generate Fourcc.
So, you can't wait to use the template to rewrite the above functions:
Template
Inline Fourcc Makefourcc ()
{
Return (CH0 << 0) (CH1 << 8) (CH2 << 16) (CH3 << 24);
}
But the wrong is old. Although this time, the return value can be calculated in the compile period, but unfortunately that the return statement has to run to run (and it is possible to eliminate this statement in the optimization phase, but must not compile each completion again).
Don't worry, there is a second foundation. what is that? It is a thing that inherits from the C language. Many friends think that it is not very important, because many cases can be used to replace it, such as const. But it has a feature that is often ignored, and this feature is very important, that is, it must be derived in the compile period, ie it is a compile period! Is this not in line with our needs? Please see the following template:
Template
Struct Makefourcc
{
Enum {value = (chain << 0) (CH1 << 8) (CH2 << 16) (CH3 << 24)};
}
The core is still the same as above, and Fourcc is calculated by expression (CH0 << 0) (CH2 << 16) (CH3 << 24) (which is of course the same). But the calculated timing moves from the runtime or optimization period to the compile period. The compiler calculates the value of the expression through the Char constant brought by the template and saves it in the enumerated value value. Take a look at the current code:
Const Fourcc Fccfmt = Makefourcc <'f', 'M', 'T', ''> :: Value; const fourcc fccdata = makefourcc <'d', 'a', 't', 'a'> :: Value ;
...
Switch (VAL)
{
Case FCCFMT:
...
Break;
Case Fccdata:
...
Break;
...
}
Successfully, the Makefourcc template completed the task. The Fourcc template generation method allows us to abandon the unsafe macro, let us see the limitations of Inline, but also let us re-recognize some of the features of Enum. Many of many similar issues can also be solved by Template Enum. They can take you into a wonderful "compile period programming" world.
I wish you all a happy program :)