【问题标题】:Programming in C: Expected constant expression error用 C 语言编程:预期的常量表达式错误
【发布时间】:2020-02-05 02:12:00
【问题描述】:

我目前正在尝试编译从 github 获取的 crc 计算器,但在 Visual Studio 2015 上编译时遇到困难。我收到错误预期常量表达式:

char paths[strlen(src) + 1 + strlen(name) + 2 + 1];

关于如何解决错误的想法?

static int create_source(char *src, char *name, FILE **head, FILE **code) {
    // for error return
    *head = NULL;
    *code = NULL;

    // create the src directory if it does not exist
    int ret = _mkdir(src, 0755);
    if (ret && errno != EEXIST)
        return 1;

    // construct the path for the source files, leaving suff pointing to the
    // position for the 'h' or 'c'.
    char paths[strlen(src) + 1 + strlen(name) + 2 + 1];
    char *suff = stpcpy(path, src);
    *suff++ = '/';
    suff = stpcpy(suff, name);
    *suff++ = '.';
    suff[1] = 0;

    // create header file
    *suff = 'h';
    *head = fopen(path, "wx");
    if (*head == NULL)
        return errno == EEXIST ? 2 : 1;

    // create code file
    *suff = 'c';
    *code = fopen(path, "wx");
    if (*code == NULL) {
        int err = errno;
        fclose(*head);
        *head = NULL;
        *suff = 'h';
        unlink(path);
        return err == EEXIST ? 2 : 1;
    }

    // all good -- return handles for header and code
    return 0;
}

【问题讨论】:

  • 使用支持 VLA 的更好的编译器。
  • 或者分配存储并且根本不使用 VLA - 从 C11 开始,编译器现在可以选择支持(或不支持)。
  • path 未定义

标签: c visual-studio-2015


【解决方案1】:

您的直接问题是您正在尝试使用 VLA(可变长度数组),该 VLA(可变长度数组)通过 C99 引入标准,编译器不支持 VLA。如果没有 VLA 支持,数组必须用 整数常量 声明(而不仅仅是 const int)。从 C11 开始,对 VLA 的支持是可选的。

要解决您当前的问题并提供可移植性,只需为paths 分配存储空间,而不是mallocfree 从函数返回之前的内存(通过错误返回或成功返回)

你可以这样做:

size_t pathlen = strlen(src) + 1 + strlen(name) + 2 + 1;
char *paths = malloc (pathlen);     /* allocate storage for paths */
if (!paths) {                       /* validate EVERY allocation */
    perror ("malloc-paths");
    return 3;   /* or however you want to handle the error */ 
}
char *suff = stpcpy(path, src);

...

*head = fopen(path, "wx");
if (*head == NULL) {
    free (path);                    /* free paths */
    return errno == EEXIST ? 2 : 1;
}

...

if (*code == NULL) {
    int err = errno;
    free (path);                    /* free paths */
    fclose(*head);
    *head = NULL;
    *suff = 'h';
    unlink(path);
    return err == EEXIST ? 2 : 1;
}

free (path);                        /* free paths */
return 0;

分配和释放的开销很小,但在你的情况下可以忽略不计,因为只有一个分配和一个释放。

【讨论】:

  • stpcpy 不在 ISO C 中
  • unlink(path) 导致UB 因为路径不是空终止的(*suff = 'h' 是最后一次写入它)。当然,假设path 意味着paths。用snprintf 替换所有这些废话似乎是一个巨大的改进
  • 很好的捕获——那些只是副本——但需要被捕获。 stpcpy 是 POSIX(不知道 VS15 是否支持它。)man 3 stpcpy 建议改为 strcpy。 (或建议的snprintf
  • 如果编译器是 C11 兼容并且不支持 VLA,它应该通过定义 __STDC_NO_VLA__ 或类似的方式来宣布这一事实。
  • 在 VS2017 之前,仅包含 C99 和 C11 标准的部分只是为了支持 C++11/14,Is there any option to switch between C99 and C11 C standards in Visual Studio?
【解决方案2】:

作为 David 解决方案的简单替代方案,您还可以使用 FILENAME_MAX ...

[...] 扩展为一个整数常量表达式,它是一个足够大的 char 数组所需的大小,以容纳实现保证可以打开的最长文件名字符串; (§7.21.1,ISO C11)

喜欢这个

char paths[FILENAME_MAX];

不过,您可能想检查一下是否没有超出此大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    相关资源
    最近更新 更多