C 中的静态、定义和常量

发布于 2024-08-28 16:58:26 字数 417 浏览 6 评论 0原文

我读过,当人们不希望每次调用函数时更改/初始化变量值时,在函数内部使用静态变量。但是,如果在主程序中的“main”之前定义一个静态变量呢?例如,

#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 转换为正确的数据类型。

I've read that static variables are used inside function when one doesn't want the variable value to change/initialize each time the function is called. But what about defining a variable static in the main program before "main" e.g.

#include <stdio.h>

static double m = 30000;

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

Here the variable m has a constant value that won't get modified later in the main program. In the same line of thought what difference does it make to have these instead of using the static definition:

const double m = 30000;

or

#define m 30000  //m or M  

and then making sure here to use double operations in the main code so as to convert m to the right data type.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

呢古 2024-09-04 16:58:26
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;

这是更好的,并且在许多情况下是最好的。如果编译器看到这个全局常量,然后看到对 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”一次在节目中。

话虽这么说,这样声明常量的情况并不少见,而且通常知道自己在做什么的人会以这种方式正确地完成它们。

static double m = 30000; 

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

This doesn't win you anything. A copy of m has to be made to do the computation.
Also if you do:

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

Then all calls to bar will change m.
Static variables outside of functions (or classes) are really global variables with file scope. Other files can't get at them by extern

Static variables inside a function are still like global variables, except that even other functions in the same file can't see them directly.

const double m = 30000;

This is better and in many cases best. If the compiler sees this global const and then sees a reference to m then it knows that rather than generate code to load the value from where ever it is (which likely requires loading a literal address into a register first) to a register or stack position to do computations it can just make a register be 30000 or sometimes generate an instruction with 30000 encoded right in there.

The down side to this is that the compiler has to assume that other souce files will want to read m and has to actually store a copy as a variable (but a constant variable) in the object file.

I'm not sure if it is standard but you can sometimes do extern const double m = 30000; and the compiler will use 30000 to optimize and assume that another file actually has a copy of m that will be stored in the executable. You can also do static const double m = 30000; and the compiler can assume that no one else will expect that a copy of m is stored in the object code generated from this source file.

Doing

#define m 30000

is more risky. You will not get a warning or error if previously there was another m declared as a variable, constant, or function. Also, for preprocessor macros like this it is easy to mess up.
For example:

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

Yes, this is a stupid example, but what this looks like after the preprocessor gets done with it is

...
  return 48+9*4;

Which is

 return 48+(9*4);

And that's not what you probably wanted.

Another place where macros are bad is when you have large constants, such as strings. Strings require that they be addressable by pointer and are more difficult to optimize away than integers and floating point literal or constant numbers. You could easily make a very large program if you had lots of stuff like:

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

and then used JIM and JOHN all over your programs because the compiler might not be able to see that you really only needed the strings "Jom" and "John" once in the program.

That being said, it is not uncommon to see constants being declared like that, and often they are properly done that way by people who know what they are doing.

锦爱 2024-09-04 16:58:26

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

static means that the variable will have static storage duration, and local visibility. In this case, it's being used for the "local visibility" part of that -- i.e. it means that m is visible only within this translation unit (essentially this file after it's prepocessed).

满地尘埃落定 2024-09-04 16:58:26

当您编写 const double m=3000; 时,您是在告诉编译器在目标文件中创建一个可以从其他文件访问的符号 m。编译器可以将 m 的值内联到定义它的文件中,但仍必须分配该符号以用于单独编译的目的。

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

When you write const double m=3000; you are telling the compiler to create a symbol m in the object file that can be accessed from other files. The compiler may inline the value of m in the file where it is defined, but the symbol still has to be allocated for the purposes of separate compilation.

When you write #define m 3000 you are just using a syntactic convenience for writing the same constant in several places in the source file.

李不 2024-09-04 16:58:26

对于在函数外部声明的对象,static 只是使该对象成为翻译单元的本地对象(即无法从其他 .c 文件访问它)。它并没有使它保持不变。这是 const 的用途。它们是正交的,因此您可以选择其中之一或两者。

例如,

static const double m = 5;

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

static for an object declared outside a function merely makes the object local to the translation unit (i.e. it can't be accessed from other .c files). It doesn't make it constant. That it was const is for. They are orthogonal so you can have one or the other or both.

e.g.

static const double m = 5;

The #define declares a macro which (in this case) can be used as a constant value. There's no object, so const doesn't apply as there's not object to be changed. As a consequence, you also can't take the address of a macro.

云裳 2024-09-04 16:58:26

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

static const double m = 30000; 

#define m 30000

只需注意,在 C const 对象中默认情况下具有外部链接,因此要得到等效的 const 声明必须使用 static const,而不仅仅是 const

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

后者通常仅是整数常数的问题。对于 double 的情况,使用 [static] const 的方法可能效果最好。

If the value of m has to stay the same forever, then of course you can either use

static const double m = 30000; 

or

#define m 30000

Just note that in C const objects have external linkage by default, so to get the equivalent const declaration you have to use static const, not just const.

Also note that in C language const objects are not constants, but rather "constant variables". If you need a true constant (i.e. an entity that forms constant expressions), you have to use either #define or enum constant.

The latter is normally an issue with integral constants only. In your case of a double the approach with [static] const might work best.

情话已封尘 2024-09-04 16:58:26

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

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

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

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

/* 
  # 1
  # 2
*/

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

因此,您的第一个没有 constm 仍然可以更改。只有 const 可以防止更改。但是,如果您省略static,那么如果您链接到在文件范围内具有相同非静态标识符的库或另一个对象文件,您将在链接时遇到冲突。

... change/initialize each time the function is called

You use the words "change" and "initialize" as though they were the same, but they aren't

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

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

/* 
  # 1
  # 2
*/

When at file-scope (outside functions) static does not mean "const" as in "static value", but it means that the identifier can only be referred to in that translation unit.

So your first m without const can still be changed. Only const guards against changes. But if you omit static then if you link in a library or another object file that has the same non-static identifier at file-scope you will get conflicts at link-time.

颜漓半夏 2024-09-04 16:58:26

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

#define is a preprocessor operation and will cause all occurrences of m to be replaced by 30000 before the compilation phase happens. The other two examples are bona fide variables. The static variable exists in the translation unit in which it is declared and can be modified. The const variable is read-only.

灰色世界里的红玫瑰 2024-09-04 16:58:26

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

使用 const#define 之间的区别在于,前者允许编译器对常量的使用进行类型检查。

In the toplevel scope static means that the variable (or function) cannot be accessed outside this source file - it won't be made available to the linker, and won't cause any name conflicts when linked in. It has no effect on whether a variable is constant or not - in fact, such variables are often specifically non-constant so that initialization can be cached.

The difference between using const and #define is that the former allows the compiler to type-check your usage of a constant.

无人问我粥可暖 2024-09-04 16:58:26

主要区别在于,使用 #define 可以离开类型系统。预处理器没有类型安全、作用域等概念。因此,例如,如果您稍后尝试编写类似

for (int m = 0; m < size; m++) { ... } 的

循环,您将会遇到一个令人讨厌的惊喜。 ..

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

The main difference is that with #define you leave the type system. The preprocessor has no notion of type safety, scope etc. So e.g. if you later try to write a loop like

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

you are up to a nasty surprise...

Also if you use #defines, you will only see the value of 30000 when debugging your code, not the name m. Which does not seem to make a big difference in this case, but when using meaningful constant and variable names, it does indeed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文