在C++中使用变量而不是`#define`来指定数组大小是不好的做法吗?(C错误:在文件范围内修改了错误)[已关闭]

wgx48brx  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(105)

已关闭,此问题为opinion-based。它目前不接受回答。
**想改善这个问题吗?**更新问题,以便editing this post可以用事实和引用来回答。

五年前就关门了。
Improve this question
在C中,使用变量声明数组大小,即使它是const变量,也是 * 不允许的 *。示例:这在C中无法编译:

#include <stdio.h>

const int SIZE = 2;
int a[SIZE];

int main()
{
    a[0] = 1;
    a[1] = 2;
    printf("%i, %i", a[0], a[1]);
    return 0;
}

Run this code in C.

gcc -o main *.c

输出量:

main.c:5:5: error: variably modified ‘a’ at file scope
 int a[SIZE];
     ^

在C++中,它运行得很好。
Run the above code in C++.

g++ -o main *.cpp
main

输出量:

1, 2

要使它在C中运行,必须使用#define而不是变量。即:
这在C * 或 * C++中运行得很好:

#include <stdio.h>

#define SIZE 2
// const int SIZE = 2;
int a[SIZE];

int main()
{
    a[0] = 1;
    a[1] = 2;
    printf("%i, %i", a[0], a[1]);
    return 0;
}

Run this code in C.
因此,在C中,我 * 几乎总是 * 使用一个变量,而不是#define,来声明我的数组大小。我只是让数组大小变量const,这一切都很好!然而,最近我开始用纯C语言进行大量的微控制器编程,当我遇到这个错误并找出问题时,一位高级开发人员告诉我,使用除了#define-ed常量(或者硬编码的数字)之外的任何东西来声明数组大小都是不好的做法。
这是真的吗?在C
中,指定数组大小时使用const变量而不是#define是不好的做法吗?如果是,为什么?**

**在C中,显然你被#define卡住了:你别无选择但在C++中,你显然至少有两个选择,那么一个比另一个好吗?**是否有一个风险,使用另一个?

更新:这是我自己的答案(10月6日添加)2023年)

这就是constexpr在C中的作用,所以这是C中最好的方法:

constexpr int SIZE = 2;
int a[SIZE];

const不同,constexpr * 可能 * 是对变量使用和修改的运行时限制,constexpr变量 * 必须 * 在编译时静态已知。在这种情况下,这是正确的方法。

相关内容:

  1. Variably modified array at file scope in C
  2. static const vs #define <--这是一个可靠的问题,非常有帮助。这肯定与我的问题有关,但我的问题 * 不是重复的,因为尽管它们都是关于const与#define的,但我的问题是一个非常特殊的情况,其中一个选项甚至在一种通常被认为是C子集的语言中不起作用。这是非常不寻常的,使我的问题成为一个更狭窄的子集,适合这个问题的广泛范围。因此,不是重复。
    1.*C
    核心指南,ES.31:不要将宏用于常量或“函数”*
  3. "static const" vs "#define" vs "enum"
    1.* 可变长数组,C99*
pgx2nnw8

pgx2nnw81#

在这件事上听从斯科特·迈耶的建议会很好。他在《Effective C++》一书中写道:

第2条:使用const、enum和inlines而不是#defines。

根据您的示例调整的项目摘要。
这一项最好叫做“更喜欢编译器而不是预处理器”,因为#define可能被视为不是语言本身的一部分。这是它的问题之一。
当你做这样的事时,

#define SIZE 2

符号名SIZE可能永远不会被编译器看到;它可以在源代码到达编译器之前被预处理器移除。因此,名称SIZE可能不会输入到符号表中。如果您在编译过程中遇到涉及使用常量的错误,这可能会令人困惑,因为错误消息可能引用2,而不是SIZE。如果SIZE是在一个头文件中定义的,而不是在您编写的头文件中定义的,那么您将不知道2来自何处,并且您将浪费时间来跟踪它。这个问题也可能出现在符号调试器中,因为您正在编程的名称可能不在符号表中。解决方案是将宏替换为常量:
const double SIZE = 2; // uppercase names are usually for macros, hence the name change
作为一个语言常量,SIZE肯定会被编译器看到,并且肯定会被输入到他们的符号表中。
对于简单常量,首选const对象或枚举而不是#defines。
对于类似函数的宏,首选内联函数而不是#defines。
另请参阅“第3项:尽可能使用const。”以了解有关其用法和用法例外的更多信息。
回答你在标题中的问题:

,在C++中使用变量而不是#define指定数组大小并不是一个坏习惯。

k4emjkb1

k4emjkb12#

我喜欢你的问题!C++正在演变成一种不再需要#define的语言。根据版本,您可以替换其他构件。这有几个原因,包括IDE的问题,用其他常量意外替换枚举值的变量名,(不要合并ERROR和)以及缺少名称空间,因为这都是预处理器替换。
对于本示例,您将创建一个C样式数组,该数组需要一个常数。然而,写入const int SIZE = 2并不会创建一个常量,它会创建一个不可变的变量。这可以用很多方法来使用,并且可以用几乎任何代码来初始化,包括通过阅读文件来计算的代码。
您正在搜索的内容是constexpr。将变量提升为编译时常数并将初始化选项限制为可在编译时执行的所有代码的关键字。所以:常数,用它们进行的计算以及对这些计算进行分组的constexpr函数。如果你想知道更多关于它,谷歌constexpr(或使用不同的搜索引擎)。

  • 注意 * constexpr需要C11,当你想写constexpr函数时,建议使用C14。对于constexpr标准库函数,如果我没记错的话,你必须等待C++20。
constexpr int SIZE = 2;
int a[SIZE];
iqih9akk

iqih9akk3#

因为SIZE被定义为const变量。在C中,与C++ const不同,值不是真常量。它们存储在内存中,可以间接引用和修改(通过修改内存中的内容)。这就是为什么在C++中有const可以允许const int SIZE = 2;工作,但即使是const在C中也是不够的。

C11-§6.7.9/3:

需要初始化的实体类型应为未知大小的数组或完整的对象类型,非变长数组类型。
预处理器宏在编译时替换,这就是为什么它工作正常。
参考链接:https://stackoverflow.com/a/35162075/5612562

相关问题