常量的好处

发布于 2024-08-27 05:47:25 字数 231 浏览 9 评论 0原文

我知道关于常量的一大问题是,您不必遍历和更新到处使用该常量的代码。这很好,但假设您没有明确将其声明为常量。采用实际上不会更改的变量并将其设为常量有什么好处,这会节省处理和/或代码大小...等吗?

基本上我有一个程序,编译器说某个特定变量没有更改,因此可以声明为常量,我只是想知道向其添加常量限定符有什么好处,如果没有区别,那么这种变化不会增加任何价值,因此没有必要浪费时间(同样的情况发生在不止一个地方)返回并“修复”所有这些变量。

I understand one of the big deals about constants is that you don't have to go through and update code where that constant is used all over the place. Thats great, but let's say you don't explicitly declare it as a constant. What benefit(s) exist(s) to take a variable that HAPPENS to actually not be changed and make it a constant, will this save on processing, and/or size of code...etc?

Basically I have a program that the compiler is saying that a particular variable is not changed and thus can be declared a constant, I just wanted to know what the benefit to adding the constant qualifier to it would be, if it makes no difference then making that change adds no value and thus no point wasting time (this same scenario occurs in more then one place) going back and "fixing" all these variables.

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

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

发布评论

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

评论(14

獨角戲 2024-09-03 05:47:25

如果您将变量声明为常量,那么优化器通常可以通过“常量折叠”消除它,从而既加快程序速度又节省空间。举个例子,考虑一下:

var int a = 5;
const int b = 7;
...
c = process(a*b);

编译器最终将创建一条将 a 乘以 7 的指令,并将其传递给“process”,将结果存储在 c 中。然而在这种情况下:

const int a = 5;
const int b = 7;
...
c = process(a*b);

编译器将简单地传递 35 进行处理,甚至不编码乘法。另外,如果编译器知道process没有副作用(即,是一个简单的计算)那么它甚至不会调用process。它只会将 c 设置为 process(35) 的返回值,从而节省了函数调用。

If you declare a variable to be a constant, then the optimizer can often eliminate it via 'constant folding' and thus both speed up your program and save you space. As an example, consider this:

var int a = 5;
const int b = 7;
...
c = process(a*b);

The compiler will end up creating an instruction to multiply a by 7, and pass that to 'process', storing the results in c. However in this case:

const int a = 5;
const int b = 7;
...
c = process(a*b);

The compiler will simply pass 35 to process, and not even code the multiply. In addition, if the compiler knows that process has no side effects (ie, is a simple calculation) then it won't even call process. It will just set c to be the return value of process(35), saving you a function call.

铃予 2024-09-03 05:47:25

如果您将某些内容声明为常量,然后意外地尝试在代码中修改其值,编译器会告诉您错误。这种形式的静态类型检查实际上是使用常量的主要原因。

If you declare something as a constant, and then accidentally attempt to modify its value in your code, the compiler will tell you about your mistake. This form of static type checking is actually the main reason for using constants.

谎言月老 2024-09-03 05:47:25

这很大程度上取决于你的优化器有多好。

一个好的优化器会在编译期间用文字值替换 const 引用。这节省了处理器周期,因为生成的机器代码使用立即值,而不必从内存加载值。

一些优化器会识别出一个值在声明后没有被修改,并将其转换为常量。不要依赖这种行为。

此外,只要有可能,您的代码就应该强制执行您在开发过程中所做的假设。如果“变量”永远不应该被更改,那么将其声明为常量将有助于确保您自己或后来出现的任何其他开发人员都不会无意中修改“常量”。

A lot of this depends on how good your optimizer is.

A good optimizer will replace const references with literal values during compilation. This saves processor cycles since the generated machine code is working with immediate values instead of having to load a value from memory.

Some optimizers will recognize that a value is not modified after it is declared, and convert it to a constant for you. Do not rely on this behavior.

Also, whenever possible, your code should enforce the assumptions you've made during development. If a "variable" should never be changed, declaring it as a constant will help ensure that neither yourself nor any other developers that come along later will unwittingly modify a "constant".

莫相离 2024-09-03 05:47:25

将变量标记为常量表明了您作为程序员的意图,即无论何时在代码执行期间访问该变量,该值都将是一致的值。将其视为一种文档形式,也会使编译器执行您的设计。

Marking a variable as constant declares your intent as a programmer that this will be a consistent value whenever it's accessed during the execution of the code. Consider it a form of documentation that also causes the compiler to enfore your design.

千と千尋 2024-09-03 05:47:25

正如您所指出的,将不变的变量更改为显式常量可能不会获得任何直接好处。然而,在分析程序时,进行的一项检查是查看变量的声明点到变量的引用点。因此,诸如在声明之前访问的变量或在引用之前设置和重置等指标可能表明可能存在错误。

通过将常量显式声明为常量,编译器和分析工具知道您不打算随时重置变量。

对于使用您的代码的其他开发人员来说也是如此。他们可能会无意中设置一个变量,而您可能没有意识到。声明常量可以避免这些类型的错误。

As you point out, you may not gain any direct benefit from changing the unchanging variables into explicit constants. However, in analysing a program one check that is made is to look at the point of declaration of a variable to the point of reference of the variable. So metrics such as variables that are being accessed before declaration, or set and reset before reference etc can indicate probably bugs.

By explicitly declaring constants as constants the compiler and analysis tools know that you do not intend to reset the variable at any time.

This is also true for other developers that work with your code. They may inadvertently set a variable and you may not be aware of it. Declaring constants will avoid these types of errors.

岁月如刀 2024-09-03 05:47:25

编译器可能会减少代码大小..例如,在包 System 中,您会发现(在 x86 机器上),

type Bit_Order is (High_Order_First, Low_Order_First);
Default_Bit_Order : constant Bit_Order := Low_Order_First;

这样

case System.Default_Bit_Order is
   when System.High_Order_First =>
      --  Big-endian processing
   when System.Low_Order_First =>
      --  Little-endian processing
end case;

编译器就可以完全消除代码时的“错误”分支保留其便携性。使用 GNAT,您需要使用非默认优化才能实现此目的:我认为 -O2 。

两个分支都必须是可编译的——这是一种优化,而不是#ifdef处理。

It's possible that the compiler could reduce code size .. for example, in package System you'll find (on an x86 machine)

type Bit_Order is (High_Order_First, Low_Order_First);
Default_Bit_Order : constant Bit_Order := Low_Order_First;

so that given

case System.Default_Bit_Order is
   when System.High_Order_First =>
      --  Big-endian processing
   when System.Low_Order_First =>
      --  Little-endian processing
end case;

the compiler can completely eliminate the 'wrong' branch while your code retains its portability. With GNAT you need to use non-default optimisation for this to happen: -O2 I think.

Both branches have to be compilable -- this is an optimisation, not #ifdef processing.

凉墨 2024-09-03 05:47:25

一个好处是,如果它确实是一个恒定值,您就不会意外地更改它。这个常数可以防止你以后把事情搞砸。作为一个变量,任何人都可以在稍后更新代码时更改它。

应该清楚哪些价值观永远不会改变,哪些价值观可以改变。常数强化你的意图。


我年轻时的真实例子:

我正在开发的系统上没有内置 PI 值,因此有人创建了一个名为 PI 的变量,在此过程中,有人(我)将该值修改为 3.14519(或其他值)有关于)在我写的程序中...不是 pi 3.14159 的近似值)。它已在代码中的其他位置设置,从那时起所有的计算都不再进行。如果那个 PI 是一个常量(当然,后来它被改变了),我就不会犯这个错误......至少不会那么容易。

One benefit is that if it is truly a constant value, you wouldn't accidentally change it. The constant keeps you from screwing stuff up later. As a variable, anyone could come along and change it later when updating the code.

It should be clear which values can never change and which values can change. Constants reinforce your intention.


Real world example from my youth:

We didn't have a built-in PI value on a system I was working on so someone created a VARIABLE called PI and somewhere along the way, someone (me) modified that value to 3.14519 (or something there abouts) in a procedure I wrote... not the approximation of pi 3.14159). It had been set elsewhere in the code, and all sorts of calculations were off from that point forward. Had that PI been a constant (it was changed later, of course), I wouldn't have been able to make that error... at least not easily.

不知在何时 2024-09-03 05:47:25

除了已经说过的内容之外,将变量声明为常量还为优化器提供了更多自由。它可以消除读取其值,可以消除创建临时副本的需要,可以消除变量本身(对于数字常量尤其如此)。

常量的另一个重要用例是常量对象。拥有一个常量对象(或者在函数中放弃对常量对象的引用),您可以确保您的对象没有被修改,并且只允许该对象的方法(称为 const 方法)叫。然而对于 C++ 来说确实如此,我不确定同样的概念在 Ada 中是否也有效。

In addition to whatever has been already said, declaring the variable as a constant gives more freedom for the optimizer. It can eliminate reading its values, it can eliminate need to create a temporary copy, it can eliminate the variable itself (this is especially true for the numeric constants).

Another big use case for the constants is constant objects. Having a constant object (or giving away a reference to a constant object in a function) you can be sure your object is not modified, and only methods (called const methods) of that object are allowed to be called. This is however true for C++, I am not sure if the same concept is valid in Ada as well.

眼角的笑意。 2024-09-03 05:47:25

另一种可能性(取决于语言)是编译器可能能够在多线程环境中进行一些原本不可能实现的优化。就像你说:

int b=x*f;
int c=y*f;

在多线程环境中,如果 f 是变量,编译器可能必须在第二个操作之前生成 f 的重新加载。如果 f 是常量并且编译器知道它仍在寄存器中,则不需要重新加载。

Another possibility, depending on the language, is that the compiler may be able to do some optimizations in a multi-threading environment that would not otherwise be possible. Like if you say:

int b=x*f;
int c=y*f;

In a multi-threaded environment, if f is a variable, the compiler may have to generate a reload of f before the second operation. If f is a constant and the compiler knows it's still in the register, it wouldn't need to reload.

淡笑忘祈一世凡恋 2024-09-03 05:47:25

当然,对于像 C 和 Ada 这样的语言,编译器会将常量中的值直接放入汇编指令中,这意味着除了运行程序所需之外,不需要交换寄存器或从内存中读取。这意味着两件事:一是速度(在许多应用程序中可能不太明显,除非它们是嵌入式的),二是内存使用量(程序的最终二进制大小及其运行时内存占用量)。

这种行为将取决于语言和编译器,因为语言将决定您(程序员)所做的任何假设,从而限制语言的效率;和编译器,因为它的行为可能会从像任何其他变量一样对待常量改变为预处理代码并尽可能优化二进制速度和占用空间。

其次,正如itsmatt和jball所说,它使您能够在逻辑上将该项视为常量配置项而不是“变量”;特别是在高级编程语言和解释语言中。

Certainly for a language like C and Ada, the compiler will put the value from the constant directly into the assembler instruction, meaning that no swapping of registers or reading from memory will be necessary over and above what is required to run the program. This means two things: the main one is speed (probably not so noticeably in many applications, unless they are embedded) and the second is memory usage (of both the program's final binary size and its runtime memory footprint).

This behaviour will come down to the language and the compiler, as the language will dictate any assumptions made by you (the programmer) and therefore the constraints to the efficiency of the language; and the compiler because its behaviour could change from treating your constant like any other variable to pre-processing your code and optimising the binary speed and footprint as much as possible.

Secondly, as was stated by itsmatt and jball, it enables you to logically consider the item as a constant configuration item rather than a 'variable'; especially in higher level programming languages and interpreted languages.

梦幻的味道 2024-09-03 05:47:25

还有另一个好处,即堆栈和数据段的大小。

考虑一下:

function Recurser(i : Integer) return Integer is
  ia : array(0..9) of Integer
          := (1, 2, 3, 4, 5, 6, 7, 8, 9, 1000);
  r : Integer;
begin
   if i = 0 then return 0; end if;
   r := ia(i mod 10);
   return r + Recurser(i - 1);
end;

每次该函数递归时,您都会在堆栈上创建一个 320 字节的结构。但由于 a 的值不会改变,因此堆栈会增加以保存恒定的变量。这对于具有小型堆栈的嵌入式平台非常重要。

包级变量也会增加数据段的大小。提高您的内存要求。

There is another benefit, stack and data segment sizes.

Consider:

function Recurser(i : Integer) return Integer is
  ia : array(0..9) of Integer
          := (1, 2, 3, 4, 5, 6, 7, 8, 9, 1000);
  r : Integer;
begin
   if i = 0 then return 0; end if;
   r := ia(i mod 10);
   return r + Recurser(i - 1);
end;

Every time that function recurses you create a 320 byte structure on the Stack. But since the value of a doesn't change the stack is increasing to hold a variable that is constant. This can be very important on embedded platforms with small stacks.

Package level variables also increase the size of the data segment. Pushing up your memory requirements.

空宴 2024-09-03 05:47:25

这实际上并不是 Ada 特有的问题。

常量相对于变量的一般好处:

  • 防止“常量”意外被修改而导致代码错误。
  • 通知编译器可以假设优化时该值不会改变。

Ada 的特定优点:

  • 对于数字常量,您不必指定类型(命名数字)。如果您以这种方式声明它,它将可以在该类型数字的任何表达式中使用。如果您改用变量,则它只能用在该变量精确类型的表达式中。

例子:

Seconds_Per_Minute : constant := 60;
Secs_Per_Min       : Integer  := 60;

type Seconds_Offset is 0 .. Integer'last; --'

Min1, Secs1 : Integer;
Min2, Secs2 : Seconds_Offset;

...
--// Using the named number, both of these compile no problem.
Secs1 := Min1 * Seconds_Per_Minute;
Secs2 :=  Min2 * Seconds_Per_Minute;

--// The second line here gives an error, since Integer is a 
--// different type than Seconds_Offset.
Secs1 := Min1 * Secs_Per_Min;
Secs2 := Min2 * Secs_Per_Min;

This isn't really an Ada-specific question.

The general benifits of constants over variables:

  • Prevents code errors from "constant" accidentally getting modified.
  • Informs the compiler that it can assume the value will not change when optimizing.

Ada specific benifits:

  • For numeric constants, you don't have to specify a type (named numbers). If you declare it this way, it will be usable in any expression for that kind of number. If you use a variable instead, it can only be used in expressions of that variable's exact type.

Example:

Seconds_Per_Minute : constant := 60;
Secs_Per_Min       : Integer  := 60;

type Seconds_Offset is 0 .. Integer'last; --'

Min1, Secs1 : Integer;
Min2, Secs2 : Seconds_Offset;

...
--// Using the named number, both of these compile no problem.
Secs1 := Min1 * Seconds_Per_Minute;
Secs2 :=  Min2 * Seconds_Per_Minute;

--// The second line here gives an error, since Integer is a 
--// different type than Seconds_Offset.
Secs1 := Min1 * Secs_Per_Min;
Secs2 := Min2 * Secs_Per_Min;
甜心 2024-09-03 05:47:25

常量通常存储在只读存储器中,这可以防止在执行过程中更改它们,并且访问它们可能会更快,或者至少与访问 RAM 一样快。

Constants are usually stored in Read Only Memory, which prevents changing them during the execution and accessing them might be faster, or at least as fast as accessing RAM.

暖阳 2024-09-03 05:47:25

常量是不可变的值,在编译时已知,并且在程序的生命周期内不会改变。

常量与变量有一个显着的区别,即一旦将值分配给常量,该值就不能再更改。

在运行时,您可以确保常量中定义的值不会更改,因此您的程序不会中断。

Constants are immutable values which are known at compile time and do not change for the life of the program.

Constants differ from variables in one significant way in that once a value has been assigned to a constant it cannot subsequently be changed.

At runtime you can be sure that the value defined in a constant won't change and consequently your program won't break.

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