【问题标题】:Is defining the length of an array with a macro "excellent practice"?用宏“优秀实践”定义数组的长度?
【发布时间】:2014-04-27 18:55:30
【问题描述】:

我正在阅读一本名为 C Programming: A Modern Approach 的书,在讨论数组的第一部分中,作者指出:

使用宏来定义数组的长度是很好的做法

然后用简单的例子:

#define N 10
...
int a[N];

我知道这与能够返回程序的源代码并更改值有关,并且将其设为宏可能会使程序员更容易,但我不确定。 为什么这是一个很好的做法,还是客观的?

【问题讨论】:

    标签: c arrays macros


    【解决方案1】:

    这是一个很好的做法,因为

    • 显然必须对数组大小进行硬编码
    • 但不应将幻数直接注入到源代码中
    • 因此,宏是一种很好的方法,可以为其命名并从源中删除它

    话虽如此,我不确定我是否同意这是最好的方法。枚举也可以工作并避免宏的一些问题(例如,难以覆盖和静默编译)。 IIRC const int 也可以。

    编译为cc:

    const int s = 1;
    int a[s];
    
    
    int main() {
    return 0;
    }
    

    Apple LLVM 版本 4.2 (clang-425.0.28)(基于 LLVM 3.2svn)
    目标:x86_64-apple-darwin12.4.0
    线程模型:posix

    【讨论】:

    • 从宏中提取的值或仅使用实际整数值之间是否存在明显的性能差异(或任何其他差异)?
    • @hancsu N10 的运行时间没有区别,因为编译后实际上没有更多的 NN10 的简单别名
    • 啊,现在我明白了。我只是担心随着这本书的普及,从年龄角度来看,当时的最佳实践可能现在不会被使用。感谢你们俩解决这个问题。
    • @hancsu 你不知道宏是如何工作的。您不会从宏中“拉”。它们被直接预编译(“PRE”-编译)到您的代码中。这也是它们如此危险的原因——它们并不比文本替换更聪明。您可以自己编写一个#define-supporting 预处理器。
    • @hancsu 我明白你的担忧,这就是为什么我解释了我认为比使用宏更好的方法。但我至少试图解释这种方法的优点。
    【解决方案2】:

    这是一个非常好的做法,C 语言规范本身说永远不要将常量埋入代码中,而是用有意义的名称来定义它们。有几种方法可以做到这一点,宏(我个人最喜欢,因为它们不使用内存)、全局变量(使用内存并且可以修改)、常量全局变量(使用内存但永远不会改变)。

    【讨论】:

    • 每次程序调用花费 4 字节的内存值得在几乎所有情况下避免运行时错误。您对宏的偏好说明了过早的优化。
    • 我在内存不足一兆字节的环境中工作。这就是为什么这是我的偏好。更好的选择是宏(C 方式)或 const 类型(c++ 方式)。
    • 问题是你不能在数组定义中使用全局作为大小。它必须是编译时间常数(除非您使用 C99)。
    • @PeterSchneider 它是用 cc 编译的。 (clang-425.0.28) (based on LLVM 3.2svn) Target: x86_64-apple-darwin12.4.0 Thread model: posix
    • 对不起,我不建议使用 clang。
    【解决方案3】:

    使用宏而不是常量整数文字的一个主要原因是,当一个值在代码中的多个位置使用时,更新单个宏值要比遍历并找到一个值的所有用途来更新要容易得多他们。

    例如,考虑以下代码:

    int a[10];
    ...
    for(i = 0; i < 10; i++) printf("%d\n", a[i]);
    ...
    myFunc(a, 10); // 10 indicates the size of the array
    

    如果您稍后决定更改数组的大小,则必须遍历并找到用于指示大小的 10 的每个实例。但是,如果我们这样做:

    #define N 10
    int a[N];
    ...
    for(i = 0; i < N; i++) printf("%d\n", a[i]);
    ...
    myFunc(a, N); // N indicates the size of the array
    

    您所要做的就是将 N 的值更改为某个新数字以更改数组的大小,您的所有其他代码都会正常工作。

    就性能而言,使用宏与硬编码常量值一样快,因为宏只是基于文本的替换。在编译时,如果宏N的值为10,那么在实际编译之前,C源代码中N的每个实例都会被更改为10

    【讨论】:

    • 我知道你只是想写一个例子,但那些 for 循环是完全错误的做法。应该始终是for(int i = 0; i &lt; sizeof(a)/sizeof(a[0]); i++),它完美地解决了这个问题。 (它在零大小的数组上失败。应该没问题。)
    • ...实际上与myFunc 相同。您实际想要的示例类似于Foo foo[10]; int someFooProperty[10];,由于某种原因,您需要两个相应的数组。
    • 我更喜欢int a[N]; myFunc(a, sizeof(a)/sizeof(a[0]));,但请使用N,就像int *a = malloc(N * sizeof(*a)); myFunc(a, N)一样。
    • 使用sizeof(a) / sizeof(a[0]) 只能在创建数组的同一上下文中使用,所以如果你在通过指针传递的数组上这样做,它是无效的。
    • @millinon 还有其他选择吗?除了原来的 i
    猜你喜欢
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多