C中的Static,define和const

时间:2010-04-09 21:29:37

标签: c static const c-preprocessor

我已经读过,当每次调用函数时不希望变量值改变/初始化时,在函数内部使用静态变量。但是如何在“主要”之前在主程序中定义变量static,例如

#include <stdio.h>

static double m = 30000;

int main(void)
{
value = m * 2 + 3;
}

此处变量m具有一个常量值,以后不会在主程序中修改。同样的想法是,它有什么不同,而不是使用静态定义:

const double m = 30000;

#define m 30000  //m or M  

然后确保在主代码中使用双重操作,以便将m转换为正确的数据类型。

9 个答案:

答案 0 :(得分:14)

static double m = 30000; 

double foo(double x, double y) {
    return x/m + y;
}

这不会赢得任何东西。必须制作m的副本来进行计算。 如果你这样做:

double bar( double x, double y) {
     m += x + y;
     return  m;
}

然后所有对bar的调用都会改变m。 函数(或类)之外的静态变量实际上是具有文件范围的全局变量。其他文件无法通过extern

获取

函数内部的静态变量仍然像全局变量一样,但是即使同一文件中的其他函数也无法直接看到它们。

const double m = 30000;

这是更好的,在许多情况下最好。如果编译器看到这个全局const,然后看到对m的引用,那么它知道而不是生成代码来从任何地方加载值(这可能需要先将文本地址加载到寄存器中)到寄存器或堆栈位置要进行计算,它只能使寄存器为30000,或者有时会生成30000编码的指令。

缺点是编译器必须假设其他源文件需要读取m并且必须将副本实际存储为目标文件中的变量(但是常量变量)。

我不确定它是否是标准的,但你有时可以extern const double m = 30000;,编译器将使用30000来优化并假设另一个文件实际上有一个m的副本,它将存储在可执行文件中。您也可以执行static const double m = 30000;,并且编译器可以假设没有其他人会期望m的副本存储在从此源文件生成的目标代码中。

否则

#define m 30000

风险更大。如果之前有另一个m声明为变量,常量或函数,则不会收到警告或错误。此外,对于像这样的预处理器宏,它很容易搞砸。 例如:

#define BASE_ADDRESS 48
#define MY_OFFSET  9
#define MY_ADDRESS  BASE_ADDRESS+MY_OFFSET
...
  return MY_ADDRESS*4;

是的,这是一个愚蠢的例子,但在预处理器完成之后看起来是什么

...
  return 48+9*4;

哪个是

 return 48+(9*4);

这不是你想要的。

宏是坏的另一个地方是你有大的常量,比如字符串。字符串要求它们可以通过指针寻址,并且比整数和浮点字面值或常数更难以优化。如果你有很多这样的东西,你可以很容易地制作一个非常大的程序:

#define JIM "Jim"
#define JOHN "John"

然后在你的程序中使用JIM和JOHN,因为编译器可能无法在程序中看到你真的只需要字符串“Jom”和“John”。

话虽如此,看到这样的常量被宣布的情况并不少见,而且通常他们是那些知道自己在做什么的人那样做的。

答案 1 :(得分:7)

static表示变量将具有静态存储持续时间和本地可见性。在这种情况下,它被用于“本地可见性”部分 - 也就是说,这意味着m仅在此翻译单元中可见(实际上是在此预处理后的文件中)。

答案 2 :(得分:5)

对于在函数外部声明的对象,

static仅使对象成为翻译单元的本地对象(即,无法从其他.c文件访问它)。它不会使它保持不变。那是const的意思。它们是正交的,因此您可以拥有一个或另一个或两者。

e.g。

static const double m = 5;

#define声明一个宏(在这种情况下)可以用作常量值。没有对象,因此const不适用,因为没有要更改的对象。因此,您也无法获取宏的地址。

答案 3 :(得分:5)

当您编写const double m=3000;时,您告诉编译器在目标文件中创建可以从其他文件访问的符号m。编译器可以在定义它的文件中内联m的值,但是为了单独编译的目的,仍然具有的符号。

当您编写#define m 3000时,您只是使用语法方便在源文件中的几个位置写入相同的常量。

答案 4 :(得分:3)

如果m的值必须永远保持不变,那么你当然可以使用

static const double m = 30000; 

#define m 30000

请注意,在C const对象中默认有外部链接,因此要获得等效的const声明,您必须使用static const,而不仅仅是const。< / p>

另请注意,在C语言中const对象不是常量,而是“常量变量”。如果你需要一个真正的常量(即形成常量表达式的实体),你必须使用#define或枚举常量。

后者通常只是积分常数的问题。在double的情况下,使用[static] const的方法可能效果最佳。

答案 5 :(得分:2)

  

...每次调用函数时更改/初始化

你使用“更改”和“初始化”这两个词,就好像它们是相同的,但它们不是

void f(void) {
  static int a = 0;
  a++; // changed!
  printf("%d\n", a);
}

int main(void) {
  f(); f();
}

/* 
  # 1
  # 2
*/

当在文件范围内(外部函数)static并不像“静态值”那样意味着“const”,但这意味着标识符只能在该翻译单元中引用。

因此,您的第一个m没有const仍然可以更改。只有const可以防范更改。但是如果省略static,那么如果链接到库或在文件范围内具有相同非静态标识符的其他目标文件,则会在链接时发生冲突。

答案 6 :(得分:2)

#define是一个预处理器操作,在编译阶段发生之前会导致m的所有出现都被30000替换。另外两个例子是真正的变量。 static变量存在于声明它的转换单元中,可以被修改const变量是只读的。

答案 7 :(得分:1)

在顶级范围static中意味着无法在此源文件之外访问变量(或函数) - 它不会对链接器可用,并且在链接时不会导致任何名称冲突它对变量是否是常量没有影响 - 实际上,这些变量通常是非常量的,因此可以缓存初始化。

使用const#define之间的区别在于前者允许编译器键入 - 检查您对常量的使用。

答案 8 :(得分:1)

主要区别在于,使用#define可以离开类型系统。预处理器没有类型安全,范围等概念。例如,如果你以后尝试写一个像

这样的循环

for(int m = 0; m&lt; size; m ++){...}

你是一个令人讨厌的惊喜...

此外,如果您使用#defines,则在调试代码时只会看到值30000,而不是名称m。在这种情况下,这似乎没有太大的区别,但是当使用有意义的常量和变量名称时,它确实存在。