C 中的静态、定义和常量
我读过,当人们不希望每次调用函数时更改/初始化变量值时,在函数内部使用静态变量。但是,如果在主程序中的“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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这不会为你赢得任何东西。必须制作 m 的副本才能进行计算。
另外,如果您这样做:
那么对 bar 的所有调用都会更改 m.
函数(或类)之外的静态变量实际上是具有文件范围的全局变量。其他文件无法通过 extern 获取它们
函数内的静态变量仍然类似于全局变量,只不过同一文件中的其他函数也无法直接看到它们。
这是更好的,并且在许多情况下是最好的。如果编译器看到这个全局常量,然后看到对 m 的引用,那么它就知道不是生成代码来将值从其所在位置(这可能需要首先将文字地址加载到寄存器中)加载到寄存器或堆栈位置为了进行计算,它可以将寄存器设置为 30000,或者有时生成一条编码为 30000 的指令。
这样做的缺点是编译器必须假设其他源文件想要读取 m 并且必须在目标文件中实际存储一个副本作为变量(但是常量变量)。
我不确定它是否是标准的,但有时您可以执行
extern const double m = 30000;
并且编译器将使用 30000 进行优化并假设另一个文件实际上具有 m 的副本存储在可执行文件中。您还可以执行static const double m = 30000;
,编译器可以假设其他人不会期望 m 的副本存储在从此源文件生成的目标代码中。做事
风险更大。如果之前有另一个 m 声明为变量、常量或函数,您将不会收到警告或错误。另外,对于像这样的预处理器宏来说,很容易搞乱。
例如:
是的,这是一个愚蠢的例子,但是预处理器完成处理后它看起来像
哪个是,
而这可能不是您想要的。
宏不好的另一个地方是当你有很大的常量时,比如字符串。字符串要求它们可以通过指针寻址,并且比整数和浮点文字或常数更难以优化。如果您有很多类似的东西,您可以轻松地编写一个非常大的程序:
然后在您的程序中使用 JIM 和 JOHN,因为编译器可能无法看到您实际上只需要字符串“Jom”和“John”一次在节目中。
话虽这么说,这样声明常量的情况并不少见,而且通常知道自己在做什么的人会以这种方式正确地完成它们。
This doesn't win you anything. A copy of m has to be made to do the computation.
Also if you do:
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.
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 dostatic 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
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:
Yes, this is a stupid example, but what this looks like after the preprocessor gets done with it is
Which is
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:
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.
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 thatm
is visible only within this translation unit (essentially this file after it's prepocessed).当您编写
const double m=3000;
时,您是在告诉编译器在目标文件中创建一个可以从其他文件访问的符号m
。编译器可以将m
的值内联到定义它的文件中,但仍必须分配该符号以用于单独编译的目的。当您编写
#define m 3000
时,您只是使用语法便利性在源文件中的多个位置写入相同的常量。When you write
const double m=3000;
you are telling the compiler to create a symbolm
in the object file that can be accessed from other files. The compiler may inline the value ofm
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.对于在函数外部声明的对象,
static
只是使该对象成为翻译单元的本地对象(即无法从其他.c
文件访问它)。它并没有使它保持不变。这是const
的用途。它们是正交的,因此您可以选择其中之一或两者。例如,
#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 wasconst
is for. They are orthogonal so you can have one or the other or both.e.g.
The
#define
declares a macro which (in this case) can be used as a constant value. There's no object, soconst
doesn't apply as there's not object to be changed. As a consequence, you also can't take the address of a macro.如果
m
的值必须永远保持不变,那么您当然可以使用或
只需注意,在 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 useor
Just note that in C
const
objects have external linkage by default, so to get the equivalentconst
declaration you have to usestatic const
, not justconst
.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.您使用“更改”和“初始化”这两个词,就好像它们是相同的一样,但它们不是
在文件范围(外部函数)
static 并不意味着“静态值”中的“const”,但它意味着该标识符只能在该翻译单元中引用。
因此,您的第一个没有
const
的m
仍然可以更改。只有const
可以防止更改。但是,如果您省略static
,那么如果您链接到在文件范围内具有相同非静态标识符的库或另一个对象文件,您将在链接时遇到冲突。You use the words "change" and "initialize" as though they were the same, but they aren't
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
withoutconst
can still be changed. Onlyconst
guards against changes. But if you omitstatic
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.#define
是一个预处理器操作,会导致所有出现的m
在编译阶段发生之前被30000
替换。另外两个例子是善意变量。静态
变量存在于声明它的翻译单元中,并且可以修改。const
变量是只读的。#define
is a preprocessor operation and will cause all occurrences ofm
to be replaced by30000
before the compilation phase happens. The other two examples are bona fide variables. Thestatic
variable exists in the translation unit in which it is declared and can be modified. Theconst
variable is read-only.在顶级作用域中,
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.主要区别在于,使用 #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.