【问题标题】:Is it possible to treat a format specifier as a variable?是否可以将格式说明符视为变量?
【发布时间】:2021-12-25 12:33:06
【问题描述】:

我希望这个函数能够根据specifier 参数从给定的time_t 参数返回数据。

如果说明符是'd',它应该返回月份中的第几天(01-31);
如果说明符是'W',它应该返回一年中的第几周(00-53)。

int get_number_atr_from_time(time_t raw_time, char specifier) {
    struct tm *info = localtime(&raw_time);

    char buffer[3];
    strftime(buffer, 3, "%specifier", info);

    return atoi(buffer);
}

这可以通过某种方式完成吗?

【问题讨论】:

  • 标题和标签提到了printf,但这里没有printf。但是要回答标题中的问题:是的,作为格式字符串传递给 printf 的字符串并没有什么特别之处。尽管您永远不应该让用户定义的数据泄漏到那里,因为使用恶意定义的格式字符串可能会导致堆栈损坏。
  • 如果您愿意,可以在运行时构造自己的格式字符串,但不能创建自己的说明符。不过,这可能是X-Y problem
  • 是的,可以做到。但是拥有两个功能不是那么简单吗?
  • 如果要将时间字段作为整数返回,用strftime转成字符串,再用atoi转它变回一个整数!这真的是你想做的吗? (是的,这确实让调用者以specifier 的形式传入strftime 将接受的任何格式说明符字符,而无需进一步解释说明符。)
  • 但是,是的,你可以按照你的要求去做。它看起来像char specString[3]; construct specString using specifier; strftime(buffer, 3, specString, info);。您所要做的就是弄清楚如何在specString 数组中构造一个合适的字符串。

标签: c time format-specifiers


【解决方案1】:

许多(如果不是大多数)采用“格式”参数的标准 C 函数,例如 printf 和 - 就像在您的代码中一样 - strftime,将该参数作为const char*。但是,这意味着它必须是字符串文字

您已声明并写入自己的任何char 数组(即不是 const)仍然可以作为const char* 参数传递。因此,您可以将所需的格式说明符写入预先声明的 format 数组,然后将其传递给 strftime 函数。

在下面的代码中,我展示了如何执行此操作以获取当前的日期和年份,分别将 'd''W' 传递给您的函数,然后写入(连同所需的% 前缀)到用于strftime 调用的格式字符串。

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

int get_number_atr_from_time(time_t raw_time, char specifier)
{
    struct tm* info = localtime(&raw_time);
    char buffer[3];
    char format[3] = { '%', specifier, 0 }; // Initialize as "%X", where X is
    strftime(buffer, 3, format, info);      // "specifier" - and add null char
    return atoi(buffer);
}

int main(void)
{
    time_t tNow = time(NULL);
    int dy = get_number_atr_from_time(tNow, 'd');
    int wk = get_number_atr_from_time(tNow, 'W');
    printf("D = %d, W = %d\n", dy, wk);
    return 0;
}

截至发布日期的输出:

D = 13, W = 45

请注意,有许多更有效的方法可以从 time_tstruct tm 值中检索日期和星期值,但上面的代码显示了如何解决您的特定问题.

【讨论】:

    【解决方案2】:

    只需使用复合文字

    strftime(buffer, 3, (char []){'%', specifier, 0}, info);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-15
      • 2014-05-04
      • 2020-10-03
      相关资源
      最近更新 更多