c 按范围快速指定整数

以前用过octave, 和matlab类似的软件, 指定范围非常方便 i = 1:10:100;  就可以得到

10 20 30 ... 100

这一系列的数据, 但是在c里面, 必须手动写循环, 太不符合懒人的习惯了, 今天写了一个宏, 终于实现了, 貌似编译器没有优化, 还是在运行时获取整数的数值,不是在编译阶段, 但是无所谓了,一般这种偷懒都是在测试的时候使用, 正式代码不会用的。

代码如下:

#include <stdio.h>
#include <stdlib.h>

#define FOR(i, ...) \
do{\
    long i, __s__##i, __e__##i,__delta__##i;\
    char *__pt__##i = #__VA_ARGS__;\
    while(*__pt__##i)\
    {\
        if((*__pt__##i < '0' || *__pt__##i > '9') && *__pt__##i != ' ' && *__pt__##i != ',' && *__pt__##i != ':')\
        {\
            if(*__pt__##i != '-' || *(__pt__##i+1) < '0' || *(__pt__##i+1) > '9')\
            {\
                fprintf(stderr, "error of F(%s,%s)\n", #i, #__VA_ARGS__);\
                    exit(1);\
            }\
        }\
        __pt__##i ++;\
    }\
    __pt__##i = #__VA_ARGS__;\
    char *__end_ptr__##i;\
    do{\
        __s__##i = strtol(__pt__##i, &__end_ptr__##i, 10);\
        while(*__end_ptr__##i == ' ') __end_ptr__##i++;\
        if(*__end_ptr__##i == ':')\
        {\
            __delta__##i = strtol(__end_ptr__##i+1, &__end_ptr__##i, 10);\
            while(*__end_ptr__##i == ' ') __end_ptr__##i++;\
            if(*__end_ptr__##i == ':')\
                __e__##i = strtol(__end_ptr__##i+1, &__end_ptr__##i, 10);\
            else\
            {\
                __e__##i = __delta__##i;\
                __delta__##i = 1;\
            }\
        }\
        else\
        {\
            __e__##i = __s__##i;\
            __delta__##i = 1;\
        }\
        for(i = __s__##i; __s__##i <= __e__##i ? i <= __e__##i: i >= __e__##i; i += __delta__##i)\
        {(void)0;

#define DO(...) __VA_ARGS__;
#define DONE(i) \
        }\
        __pt__##i = __end_ptr__##i;\
        while(*__pt__##i == ' ' || *__pt__##i == ',') __pt__##i++;\
    }while(*__pt__##i);\
}while(0);

int main(void)
{
    FOR(i, 1 2 -3 , -1:10 99:100 999 11:11, 111:3:119,1:-1:-1);
    DO(
            FOR(j, 88:2:91);
            DO(
            printf("i = %ld, j = %ld\n",i, j)
            );
            DONE(j);
      );
    DONE(i);
    return 0;
}

定义变量使用##是为了防止嵌套使用时候的变量冲突。

逗号和空格可做分隔符, 冒号作为范围指定标记, a:b代表 从a到b, b必须大于a, 增量为1,包含两端, a:b:c  可以包含两端, b为增量, a < c b为正数, a>c b为负数。

范围错误获取不到数值不会报错, 但输入非法会报错,  -后面不紧跟数字会报错, 有abc等非数字字符,包括+也会报错,具体情况看代码。

使用的变量都是{}内的局部变量,对外面不会有影响。理论上和外面的变量名字冲突了也不会有影响。

 

测试代码

i分别取 1 2 -3 -1 0 1 2 3 4 5 6 7 8 9 10 99 100 999 11 111 114 117 1 0 -1

每一个i j分别取 88 90

FOR() DO() DONE()后面的; 可有可无,因为多余的; 编译器会兼容, gcc clang 测试都不会有警告, 如果没有; 可能vim等编辑器在对齐的时候会遇到麻烦。

编译, 执行,打印结果为预期结果。

 

 

i = 1, j = 88
i = 1, j = 90
i = 2, j = 88
i = 2, j = 90
i = -3, j = 88
i = -3, j = 90
i = -1, j = 88
i = -1, j = 90
i = 0, j = 88
i = 0, j = 90
i = 1, j = 88
i = 1, j = 90
i = 2, j = 88
i = 2, j = 90
i = 3, j = 88
i = 3, j = 90
i = 4, j = 88
i = 4, j = 90
i = 5, j = 88
i = 5, j = 90
i = 6, j = 88
i = 6, j = 90
i = 7, j = 88
i = 7, j = 90
i = 8, j = 88
i = 8, j = 90
i = 9, j = 88
i = 9, j = 90
i = 10, j = 88
i = 10, j = 90
i = 99, j = 88
i = 99, j = 90
i = 100, j = 88
i = 100, j = 90
i = 999, j = 88
i = 999, j = 90
i = 11, j = 88
i = 11, j = 90
i = 111, j = 88
i = 111, j = 90
i = 114, j = 88
i = 114, j = 90
i = 117, j = 88
i = 117, j = 90
i = 1, j = 88
i = 1, j = 90
i = 0, j = 88
i = 0, j = 90
i = -1, j = 88
i = -1, j = 90

如有错误, 欢迎更正。

本文和代码欢迎复制,但不做任何保证, 不承担任何责任,可用作商业用途,但不准拿去申请专利,对于副本也如此。

posted @ 2015-04-18 17:03  yiifburj  阅读(212)  评论(0编辑  收藏  举报