C++保证编译单元(.cpp文件)中的变量按声明顺序初始化.对于编译单元的数量,此规则分别适用于每个(我的意思是类外的静态变量).
但是,变量的初始化顺序在不同的编译单元中是不确定的.
我在哪里可以看到关于gcc和MSVC的这个订单的一些解释(我知道依赖于这是一个非常糟糕的想法 - 它只是为了理解我们在迁移到新的GCC主要和不同操作系统时遗留代码可能遇到的问题) ?
我对函数中静态变量的底层实现感到好奇.
如果我声明一个基本类型的静态变量(char,int,double等),并给它一个初始值,我想编译器只是在main()调用之前在程序的最开始设置该变量的值.:
void SomeFunction();
int main(int argCount, char ** argList)
{
// at this point, the memory reserved for 'answer'
// already contains the value of 42
SomeFunction();
}
void SomeFunction()
{
static int answer = 42;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果静态变量是类的实例:
class MyClass
{
//...
};
void SomeFunction();
int main(int argCount, char ** argList)
{
SomeFunction();
}
void SomeFunction()
{
static MyClass myVar;
}
Run Code Online (Sandbox Code Playgroud)
我知道直到第一次调用该函数时才会初始化它.由于编译器无法知道第一次调用函数的时间,它是如何产生这种行为的?它本质上是在函数体中引入if块吗?
static bool initialized = 0;
if (!initialized)
{
// construct myVar
initialized = 1;
}
Run Code Online (Sandbox Code Playgroud) 我有这样的代码:
struct Storage
{
static int GetData()
{
static int global_value;
return global_value++;
}
};
int free_func()
{
static int local_value;
return local_value++;
}
int storage_test_func()
{
return Storage::GetData();
}
Run Code Online (Sandbox Code Playgroud)
在OSX上编译它:
$ clang++ 1.cpp -shared
Run Code Online (Sandbox Code Playgroud)
并运行nm:
$ nm | c++filt
Run Code Online (Sandbox Code Playgroud)
我得到了奇怪的结果:
0000000000000f50 T storage_test_func()
0000000000000f30 T free_func()
0000000000000f60 unsigned short Storage::GetData()
0000000000001024 bool free_func()::local_value
0000000000001020 D Storage::GetData()::global_value
U dyld_stub_binder
Run Code Online (Sandbox Code Playgroud)
两个符号(local_value和global_value)有不同的联系!一个明显的区别是global_value静态成员函数local_value中定义的并且在自由函数中定义.
有人能解释为什么会这样吗?
UPD:
评论阅读之后看起来我应该澄清一些事情.也许使用c++filt是一个坏主意.没有它,它显示:
$ nm
0000000000000f50 T __Z17storage_test_funcv
0000000000000f30 T …Run Code Online (Sandbox Code Playgroud) 来自在C世界中受过训练的程序员,这是我对OCaml的主要方法.
let main () =
Printf.printf "Hello, world - %d %s\n" (Array.length Sys.argv) Sys.argv.(0)
;;
main ()
Run Code Online (Sandbox Code Playgroud)
但是,这段代码适用于ocaml/ocamlc/ocmalopt.
Printf.printf "Hello, world - %d %s\n" (Array.length Sys.argv) Sys.argv.(0)
;;
Run Code Online (Sandbox Code Playgroud)
这背后的逻辑是什么?OCaml是否类似于脚本语言(即使它用ocamlc或ocamlopt编译成二进制),因为它不需要main函数?
与Scala相比,我们可以从App扩展,以便不定义main方法.
object Hello extends App {
class A
println(new A() getClass())
print("Hello, world")
}
Run Code Online (Sandbox Code Playgroud)
即使在这种情况下,我们也需要 Hello.main(args)在解释器模式下执行它:即,scala hello.scala.OCaml似乎不需要对ocaml(解释),ocamlc和ocamlopt(编译)进行任何更改.
那么,我们是否需要OCaml中的主要功能?如果是这样,OCaml是否只是从代码的开头到结束生成代码?如果是这样,OCaml如何找到具有多个源代码的主代码?
当我尝试编译这样的 C++ 代码时,需要 71 秒:
#include<bits/stdc++.h>
struct S{int v=1;}a[1<<25];
int main(){
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,当我将 1 更改为 0 时,它只需 1 秒即可编译:
#include<bits/stdc++.h>
struct S{int v=0;}a[1<<25];
int main(){
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用类似的东西S(){v=1;},但我只想知道这个有趣的区别。
System: MacOS 12.4
Compiler: g++-11 (Homebrew GCC 11.3.0_2) 11.3.0
Run Code Online (Sandbox Code Playgroud) 所以我一直在研究一个问题,这个想法偶然发现了我。当我在 main 函数之外声明一个变量时,程序正常工作,即它达到了“Friendship is magic”的 else 情况,但如果变量在内部声明,则返回 Chris 而不是 Friendship 语句。
int mis, chr;
int main() {
int a, n, m;
cin >> a;
for (int i = 0; i < a; i++) {
//code here
}
if(mis > chr)
cout << "Mishka";
else if(chr > mis)
cout << "Chris";
else
cout << "Friendship is magic!^^";
}
Run Code Online (Sandbox Code Playgroud)
我使用的输入使 chr 和 mis 的值相等,因此它应该评估 else 语句,但它只是在 else if 处停止。