为什么"C和C++"中的"static"关键字有这么多含义?

27

众所周知,在C语言中,关键字static多种含义。 C99还增加了合法编写的可能性。

void foo (int arr[static 50])
{
    // ...
}

这增加了混淆,而且C++有静态成员变量和函数。

如果所有用法可以以某种方式连接起来,那么这不会那么麻烦,但我发现对于某些情况很难找到这种连接。特别是为什么应该使用static关键字来修改可见性(链接),或者它与数组的最小元素数量有什么关系。

那么,滥用static关键字是否有历史原因,或者在幕后是否存在将其所有用法连接起来的秘密联系?


1
在示例代码中,那个语法是什么意思? - Kos
3
这意味着“arr”参数保证至少有50个元素。 - user1481860
1
请点击这里 - user1481860
5个回答

25

在一门语言中添加新的关键字会破坏向后兼容性。因此,static 被用在可能意味着某些内容的地方(例如:int arr[static 50] vs int arr[auto 50]int arr[extern 50]),并且不能在该位置上出现,基于其在之前版本中的使用。

虽然在这种情况下,在该位置添加一个not_less_than 的上下文敏感关键字不会破坏先前代码,但它会添加另一个关键字(因此简单的文本编辑器虽然知道关键字但不了解语法,但无法确定它是否为关键字),并且打破了 C 中“关键字不是上下文敏感”的简化规则。


14
如果把“not_less_than”作为保留字添加进去,如果之前的代码中有一个变量名叫做“not_less_than”,那么这个代码就会出现问题,这就是所谓的破坏向后兼容性。 - Josh Kelley
3
是的,我认为“重复使用”关键词的主要原因是我们确信没有任何明智的人在其代码中使用它作为标识符甚至#define - aschepler
7
@Øystein: 有一句名言(如果我没记错的话)是Ritchie说他想改变一些运算符的优先级,但他们有三个安装和数十万行代码。C语言在设计之前就已经成型了。 - David Thornley
4
有时候在没有其他关键字的情况下,添加另一个结构是没有明显方法的。C++委员会使用了许多互联网搜索工具来检查大量代码以寻找潜在的新关键字(因此他们知道像nullptr这样的关键字不太可能破坏任何人的代码),但在上个世纪,当static有所有这些含义时,这并不是真正可能的事情。 - David Thornley
1
@7vies:这正是C++委员会对文件作用域含义所做的事情:引入了匿名命名空间,并弃用了static的使用(第D.2节)。至于C委员会为什么没有这样做,我只能猜测原因。 - David Thornley
显示剩余9条评论

4
我知道的 C++ 中 static 的三种含义可以用一句简单的话来记住:static 意味着“与全局变量/函数非常相似,但仅在以下范围内直接可用...”
  • 如果在全局范围内,则为“此文件”。
  • 如果在函数中(包括成员函数),则为“此函数”。请注意,如果在函数中创建类和lambda,则它们仍在此范围内。具有空捕获的 Lambda 可以访问其“父”函数的静态变量。
  • 如果在类中(包括使用struct声明的类),则为“此类”。这种情况略有不同,因为你可以通过对象或前缀访问变量/函数,但这有点像要求类或其对象提供对其的访问权限,而实际上可能会被拒绝(使用private)。因此,访问不是“直接”的。

在所呈现的 C99 数组语法中,这是完全不同的东西,我认为它存在的目的是为了不引入新关键字,正如其他人所建议的那样。


2

static在C++中最初的意思已经被弃用,现在用匿名命名空间代替。目前在C++代码中实际使用static的唯一方式是作为非成员。


5
你是否忘记了函数级别的静态变量?(这种使用方式并未被废弃。)我不确定这是否是 C 中 static 的“原始含义”,但我相信这种用法在 C++ 之前就存在了。 - Fred Nurk
@Fred:static 的原始含义是文件作用域变量。虽然忘了函数级静态变量,但我认为函数级和类级静态变量在概念上足够相似,不足以被视为多个含义。 - Puppy
@DeadMG:C99的static似乎有着相当不同的含义。 - Roman L
2
其实是我提出了这个问题 :) 我的问题是关于“static”有多重含义背后的历史。这自然可以追溯到C语言,这个关键字起源于C语言。我提到C99和C++,因为这些语言也有“static”的多重含义。我猜想C#也有一些类似的东西,但我不太熟悉,不能确定。 - user1481860
5
在 C++0x(n3225)中,它不再被弃用。 - Johannes Schaub - litb
显示剩余5条评论

1

我认为这个关键字的不同用法有不同的原因。如果我们将经典C语言的函数作用域和文件作用域用法视为理所当然(它们至少是相似的概念),那么第一个离题的补充是在C++中使用static来命名类的全局成员。

我猜这里的快捷方式只是因为“static”和“global”看起来足够接近,早期的C++非常小心地不引入会破坏现有代码的新关键字。因此,他们采用了一个不能出现在该上下文中的现有关键字。

对于C99附加的数组参数,情况就不同了,我认为这里不仅有static的添加。您还可以使用类型限定符(constvolatile)来限定隐式指针:

void toto1(char str[const 5]);
void toto2(char*const str);

定义兼容的原型。我只能猜测,为了你提到的目的(数组的最小长度),选择存储类别说明符static可能被视为该语法的自然扩展。同时,很可能证明这种用法与语言的其他部分兼容,因为可以通过论证类型限定符可以用于扩展语言的地方,而存储类别说明符则不会造成太大的伤害。


-6

13
这可能是对问题的不错评论,但并不是一个好的回答。 - Fred Nurk
7
但是C是一匹马,而且是一匹优秀的马。 - Matt Joiner
这就是你问“是否有历史原因”这样的问题时得到的答案类型。但这并不意味着它是一个好答案。 - Cody Gray
我想这可能被解释为一种说法:“没有已知的历史原因”,这也许是情况如此。我意识到有时会做出奇怪的决定,但我希望有人能够提供历史课程或者能够建立低级别的联系。 - user1481860
1
问题是“为什么”。我同意通常对“为什么”问题没有好的答案,但这也不是一个好的答案。这也不一定与标准化委员会有任何关系:在C标准化之前,“static”有两个不同的含义(函数的文件作用域,变量的持久性)。 - David Thornley
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接