翻转计数器跳零

Roll over counter skipping zero

也许是一个简单的问题,但我无法理解它。

我正在做某种月份计数器,想法是用户可以按 - 或 + 并仍然达到所需的月份: 例如我有: 今天是二月所以像这样 用户按 - 2 1 12 11 10 9 ...... 有些适合 + 问题是我不想显示零

SINT16 tempVal = pDate->month + upDown;
    if (tempVal < 0) {
        tempVal += (12+1);
    } 
    pDate->month % (12 + 1);

这就是我想出的 - 它滚动到 12 然后是 0 或 1 0 12 但我想摆脱零。 任何帮助将不胜感激:)

如果 tempVal 变为零,则将月份设为 12,否则将其增加 1:

SINT16 tempVal = pDate->month + upDown;
    if (tempVal == 0) {
        pDate->month = 12;
    }//if month becomes more than 12,ie 13
    else if(tempVal %12 == 1)
    {
       pData->month = 1;
    }
    else
    {
        pDate->month = tempVal;
    }

问题很不清楚,我试试看

SINT16 tempVal = pDate->month + upDown;
if (tempVal < 0) {
    /* if you are at negative 1 - assuming upDown is either (1,-1) */
    tempVal += (12); //just add the cycle value
} 

//pDate->month % (12 + 1);
pDate->month = (pDate->month % 12) + 1;//modulo by the cycle and then shift output

需要明确的是,模 12 将输出值 (0 - 11),因此 +1 不应包含在模函数中

通过仔细选择比较,您可以简化 '%' 的使用。不是检查 month = 12month < 0,而是检查增量是否导致 month > 12month < 1。这些是需要滚动到 112 的点。

例如,在按某个值 chg 递增/递减月份的通用函数中,您只需将 chg 添加到当前月份,然后应用测试,使用 [=22] 进行更正=] where month > 12 或通过设置 month = month + 12 where month < 1,例如:

int monthchg (int *m, int chg)
{
    *m += chg;

    if (*m > 12)        /* if month > 12, roll to month % 12 */
        *m = *m % 12;
    else if (*m < 1)    /* if month < 1, add 12 to month */
        *m += 12;

    return *m;
}

将键盘置于非规范或原始模式并接受 +/- 输入更改月份或 q 退出的简短示例可能是:

#include <stdio.h>
#include <termios.h>

typedef struct {
    struct termios old;     /* orig keyboard settings   */
    struct termios new;
} kbmode;

kbmode *setkbmode (kbmode *k);
kbmode *restorekbmode (kbmode *k);

int monthchg (int *m, int chg)
{
    *m += chg;

    if (*m > 12)        /* if month > 12, roll to month % 12 */
        *m = *m % 12;
    else if (*m < 1)    /* if month < 1, add 12 to month */
        *m += 12;

    return *m;
}

int main (void) {

    kbmode kb = { .old = {0} };
    int dir, month = 6;

    setkbmode (&kb);        /* set kbd in raw-unbufered mode */

    printf ("enter +/- to inc/decrement month ('q' to quit)\n");
    for (;;) {
        printf ("\n  month : %2d : ", month);
        fflush (stdout);
        dir = getchar();

        if (dir == '+')
            monthchg (&month, 1);
        else if (dir == '-')
            monthchg (&month, -1);
        else if (dir == 'q')
            break;
        else
            puts ("invalid input - try again.");
    }
    putchar ('\n');

    restorekbmode (&kb);    /* restore original kbd settings */

    return 0;
}

/* set keyboard in raw-unbufered mode */
kbmode *setkbmode (kbmode *k)
{
    if (tcgetattr (0, &(k->old))) { /* save orig settings   */
        fprintf (stderr, "setkbmode() error: tcgetattr failed.\n");
        return NULL;
    }   /* copy old to new */
    k->new = k->old;

    k->new.c_lflag &= ~(ICANON);  /* new kbd flags */
    k->new.c_cc[VTIME] = 0;
    k->new.c_cc[VMIN] = 1;
    if (tcsetattr (0, TCSANOW, &(k->new))) {
        fprintf (stderr, "setkbmode() error: tcgetattr failed.\n");
        return NULL;
    }

    return k;
}

kbmode *restorekbmode (kbmode *k)
{
    /* reset original keyboard  */
    if (tcsetattr (0, TCSANOW, &(k->old))) {
        fprintf (stderr, "restorekbmode() error: tcsetattr failed.\n");
        return NULL;
    }

    return k;
}

例子Use/Output

$ ./bin/month_roll
enter +/- to inc/decrement month ('q' to quit)

  month :  6 : -
  month :  5 : -
  month :  4 : -
  month :  3 : -
  month :  2 : -
  month :  1 : -
  month : 12 : -
  month : 11 : -
  month : 10 : +
  month : 11 : +
  month : 12 : +
  month :  1 : +
  month :  2 : -
  month :  1 : -
  month : 12 : -
  month : 11 : -
  month : 10 : +
  month : 11 : +
  month : 12 : +
  month :  1 : +
  month :  2 : +
  month :  3 : q

检查一下,如果您还有其他问题,请告诉我。

我的建议是在代码内部以 [0, 11] 格式保留您的月份计数器,使用 modulo(12) 环绕。这很简单,并且易于理解代码。 然后编写一个函数,将内部表示 [0, 11] 映射到用户希望看到的内容,即 [1, 12],无论何时打印或以某种方式向用户显示值。

int16_t display_month(int16_t month)
{
    return month + 1;
}

在这种情况下,return 月 + 1 非常简单,但在更一般的情况下,将 N 的计数映射到与 [0, N-1] 不匹配的值,我会使用存储此映射的数组。这样,映射实际上可以是任何东西,不必按顺序排列,也不需要事件必须是整数。

int16_t display_month(int16_t month)
{
    static int16_t index_to_month_map[] = {1,2,3,4,5,6,7,8,9,10,11,12}; 
    return index_to_month_map[month];
}