1

I have some legacy code that contains this typedef:

typedef enum simple_op_enum {
    #define SOP(OPCODE, NAME, FORM, SUIFOP) OPCODE ,
    #include "simple_ops.def"
    LAST_OP
} simple_op;

The #include file contains several lines of the form:

/*  no operand instructions */
SOP( NOP_OP,    "nop ",     BASE_FORM,  io_nop)

The token "simple_op" occurs later in a struct:

typedef struct simple_instr_struct {
    simple_op opcode;           /* the opcode */

There are several things I don't understand:

  1. What is accomplished by having a comma at the end of the #define statement? I thought that was illegal.

  2. What is being accomplished by the enum, especially LAST_OP

  3. How do I access the value of opcode in a simple_instr_struct?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Schemer
  • 1,635
  • 4
  • 19
  • 39
  • http://stackoverflow.com/questions/264269/what-is-a-good-reference-documenting-patterns-of-use-of-x-macros-in-c-or-possib – M.M Nov 29 '15 at 00:05

5 Answers5

1
  1. It's not illegal, it's part of what the preprocessor will replace all instances of SOP(x, y, z) with.

  2. It's creating an enumeration with the contents in simple_ops.def. Because the contents of that file are SOP(w, x, y, z) they will all turn into w, and the enum will be:

typedef enum simple_op_enum {
   NOP_OP , // <- notice the space before the comma, like the #define does
   ...      // the others
   LAST_OP
} simple_op;

It also makes LAST_OP the last enumeration value. This is probably so the code can use LAST_OP to determine how many enum values there are (or the highest enum value, or something like that).

This #include thing is a clever trick so that the definitions can be all in the same place (the file) and the code that #includes it just defines SOP to be whatever it needs it to be. Then modifying that one file will affect the entirety of the code that needs it and the code uses them in whatever way it needs. For instance, some code might only need the name, so it would define SOP as #define SOP(w, x, y, z) x to extract the name.

3) You can access it by doing simple_instr_struct_instance.opcode

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
1

If in doubt about macros, you can always use the preprocessor to see how they expand:

gcc -E file.c -o file.txt

The output will be large if there are many header files included, but you will find your macros in there somewhere - probably towards the end

William Morris
  • 3,554
  • 2
  • 23
  • 24
0

it will extract out the opcodes as enums

enums need comma seperating, so its taking the OPCODE and putting a , after it which effectively generates

typedef enum simple_op_enum {
NOP_OP, BLAH , WHATEVER , ANOTHER ,
LAST_OP
} simple_op;

The point of the enum is to have an enum of all the opcodes available.

LAST_OP is useful for knowing things like how many opcodes you end up with, and also means there is no dangling comma for the last thing in the enum list.

if you have a instance of the struct , 'blah', then you get it by going blah.opcode = NOP_OP;

Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
0

Comma at end of #define is legal. it's part of the macro. constants of enums are separates by comma, and this macro worries to that.

enum is just a var that can contain any of the values you specify in the enum declaration. since them are translated to numbers, LAST_OP will be equal to the number of possibilities.

you can access the member like:

struct simple_instr_struct a;
a.opcode=LAST_OP;
asaelr
  • 5,438
  • 1
  • 16
  • 22
0
  1. The comma is just part of the text replacement that will occur when the macro is used. In this case, it's to add a comma after each opcode, so that the list will make valid enum syntax.

  2. The result of the #define and #include is an enumeration that looks like:

    typedef enum simple_op_enum {
      NOP_OP,
      .
      .
      .
      LAST_OP
    } simple_op;
    

    You can see the same by looking at the output of running your source code through the C preprocessor. LAST_OP is just the last entry in your new enumeration.

  3. You'll need to define a variable of that type:

    struct simple_instr_struct myStruct;
    

    and then access the field you care about:

    myStruct.opcode
    
Carl Norum
  • 219,201
  • 40
  • 422
  • 469