Putting loop inside C macro

2019-02-26 03:29发布

I'm looking for a way to convert the following function structure to a macro. I know, it's a silly and pointless example, but it illustrates the point since I cannot give out my actual source code.

int foo(int x, int y)
{
  do
  {
    --x;
    ++y;
  }while(x > y);

  return x * y; //note that x and y have changed values here.
}

So that I can call the function in main or some other function like so:

int next_x = foo(x,y);

I cannot seem to get the syntax 100% correct here. This is my poor attempt:

#define FOO(x,y)      \
(                     \
  do                  \
  {                   \
    --x;              \
    ++y;              \
  }while(x < y),      \
  x                   \
)                     

The reasoning for the x at the end is so that I could, in theory, be able to do this

int next_x = FOO(x,y);

but instead, I get a syntax error and I'm not sure why. Any help would be appreciated.

===============================================

Additional Info

I should also note that I have other macros which are structured accordingly:

#define INIT(x,y)   
(   
  x = //something,
  y = //something
)

#define NEXT_INT(x,y)    \
(                        \
  INIT(x,y),             \
  get_next_num(x,y)      \            //Note, this is an inline function call , not a macro.
 )

#define NEXT_FLOAT(x,y,temp)         \
(                                    \
  temp = NEXT_INT(x,y),              \
  temp ? temp * 1.23456 : FLT_MIN    \
)                                    

And so, I can and have done the following:

float my_flt = NEXT_FLOAT(x,y,temp);

3条回答
The star\"
2楼-- · 2019-02-26 04:18

The C syntax only allows expressions to be separated by the comma operator (,). do ... while() is not an expression, but a statement, so it is an error to use it as a value to a comma operator.

Generally speaking, an inline function should be preferred over a macro to perform some inline computation. They are easier to implement, less error prone, and easier to maintain. There are very few situations where an inline function would fail where a macro would succeed.

There really isn't a safe macro to achieve your objective, but a workaround would be to pass the variable you want updated in as a macro parameter.

#define FOO(x, y, result) \
    do { \
        do { \
            --x; \
            ++y; \
        } while(x > y); \
        result = x * y; \
    } while(0)

If you are using GCC, you can use their statement-expression syntax, which is an extension to C, and not a standard C feature. The syntax is like:

({ statement; statement; expression; })

And the result of the above would be the last expression.


In a comment, you express:

I need to save the new values of x and y for subsequent calls to this function foo.. The obvious way to do this would be to pass pointers to x and y and then just make a regular, inlined function. However I do not want to do that because I'm making a time critical application and I need x and y to remain in registers.

You are assuming that x and y would not be left in registers, which is bad assumption to make. It depends on the quality of your compiler's ability to optimize code. Consider the following:

static inline int foo (int *x, int *y) {
    do {
        --*x;
        ++*y;
    } while (*x > *y);
    return *x**y;
}

int main (int argc, char *argv[]) {
    int x = argc+1;
    int y = argc;
    foo(&x, &y);
    return 0;
}

When compiled with gcc -O1, the result is:

main:
.LFB14:
        movl    %edi, %edx
.L2:
        movl    %edi, %eax
        addl    $1, %edx
        subl    $1, %edi
        cmpl    %edx, %eax
        jg      .L2
        movl    $0, %eax
        ret
.LFE14:

You will observe there is no pointer value dereference, which is exactly what you wanted to have happen.

查看更多
3楼-- · 2019-02-26 04:18

You cannot use do/while loops as an expression, so you'll need to use a block within parentheses, like this:

EDIT: this is a GCC extension, not standard C

#define FOO(x,y)    \
({                  \
  do                \
  {                 \
    --x;            \
    ++y;            \
  }while(x > y);    \
  x;                \
})
查看更多
Fickle 薄情
4楼-- · 2019-02-26 04:18

One issue here is that multiline macros require a \ at the end of each line.

查看更多
登录 后发表回答