还有一个static问题.我看过以下内容:
我仍然无法理解以下行为:我有一个h文件:
// StaticTest.h
#include <stdio.h>
static int counter = 0;
struct A {
A () {
counter++;
printf("In A's ctor(%d)\n", counter);
}
~A () {
counter--;
printf("In A's dtor(%d)\n", counter);
}
};
static A a;
Run Code Online (Sandbox Code Playgroud)
还有两个cpp文件:
// StaticTest1.cpp
#include "StaticTest.h"
int main () {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
和:
// StaticTest2.cpp
#include "StaticTest.h"
Run Code Online (Sandbox Code Playgroud)
该计划的输出是:
In A's ctor(1)
In A's ctor(2)
In A's dtor(1)
In A's dtor(0)
Run Code Online (Sandbox Code Playgroud)
现在,A构造函数被调用两次,因为h文件被包含两次,并且因为声明了 …
我正在尝试用C++开发一个动态库,由用IDL(交互式数据语言)编写的现有程序调用.我知道我需要使用extern"C"来禁用名称修改,以便IDL可以调用它需要的函数(其余的调用机制非常简单).
但是,我总是对使用我不完全理解的语言的功能犹豫不决,所以我的问题是:如果有的话,我会通过恢复到C链接而丢失C++的哪些功能?我认为命名空间是一个显而易见的,但它是否完全禁用了C++的所有其他优点?我还可以使用C++ STL,以及我所依赖的所有各种语言功能(特别是C++ 11)吗?还是我坚持用C编码?
我正在尝试与 C 库交互,该库希望我提供一个指向回调函数的指针。
据我了解,根据标准,由于调用约定可能不同,回调必须具有 C语言链接。我可以通过将回调函数声明为extern "C". 然而,这有一个不受欢迎的副作用:将函数的未限定和未混淆的名称暴露给其他翻译单元。
是否可以声明一个函数,使其名称具有内部链接(对其他翻译单元不可见),但可以仅使用标准 C++ 通过指针(具有适当的调用约定)从 C 调用?
如果不可能让它有内部链接,至少有可能让它保持它的 C++ 名称修改吗?
我试过:
static extern "C" void f();which 导致编译错误,从而导致static和extern "C"不能一起使用。namespace { extern "C" void f(); },结果证明与常规命名空间具有相同的效果,暴露了未修饰的非限定名称。我在编译时看到了这条警告信息(gcc 4.6.3,ubuntu)示例:
struct {
} a;
int main()
{
}
warning: anonymous type with no linkage used to declare variable ‘<anonymous struct> a’ with linkage [enabled by default].
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会不会发出此警告.只有G ++才有.
添加静态清除警告:
static struct {
} a;
Run Code Online (Sandbox Code Playgroud)
我无法弄清楚它意味着什么,特别是为什么type与之相关linkage.我认为链接取决于声明变量的位置和方式,而不取决于变量本身的类型.
在研究此问题的答案的过程中,我发现(以前不知道)gcc和clang char如果声明了数组,则它们可以作为模板参数static。例如,此代码使用gcc和clang进行编译:
#include <type_traits>
template <int N, const char (&string)[N]>
auto foo()
{
if constexpr (string[0] == 'i')
return 0;
else
return 3.14f;
}
void bar()
{
static constexpr char string1[] = "int";
static constexpr char string2[] = "float";
auto i = foo<sizeof(string1), string1>();
auto f = foo<sizeof(string2), string2>();
static_assert(std::is_same_v<decltype(i), int>);
static_assert(std::is_same_v<decltype(f), float>);
}
Run Code Online (Sandbox Code Playgroud)
MSVC也允许这样做。但是,要使其与MSVC一起使用,我必须在全局名称空间中声明两个字符串。然后它也一样有效。
所以我的问题是:标准对此有何表述?哪个编译器(如果有)是正确的?
当我只是检查哪些链接被授予外部局部变量时,
我发现编译器之间的一些不同行为
例如,如果我测试了下面的代码,
正如您在评论中看到的那样,变量vars 有不同的链接
// foo.cpp
int var = 10; // external linkage
// main.cpp
#include <iostream>
static int var = 100; // internal linkage
int main() {
extern int var; // internal linkage
std::cout << var << std::endl;
{
extern int var; // g++: external linkage , clang++: internal linkage
std::cout << var << std::endl;
{
extern int var; // g++: external linkage , clang++: internal linkage
std::cout << var << std::endl;
}
}
}
Run Code Online (Sandbox Code Playgroud)
结果是 …
请参阅以下代码:
/* first file */
int i; /* definition */
int main () {
void f_in_other_place (void); /* declaration */
i = 0
return 0;
}
/* end of first file */
/* start of second file */
extern int i; /* declaration */
void f_in_other_place (void){ /* definition */
i++;
}
/* end of second file */
Run Code Online (Sandbox Code Playgroud)
我知道外部对象有external链接,内部对象有none链接(extern暂时忽略)。现在,如果我谈论函数f_in_other_place(),它是在 main 函数中声明的。那么它的标识符会被视为内部对象吗?如果是,则它应该具有none链接,但在程序中可见,此函数指的是它在第二个文件中的定义,该文件显示它的标识符的行为类似于具有external链接的对象。所以我很困惑这里的这个标识符是否有external链接或none链接?
现在谈到extern关键字,我在某处读到了函数声明隐式前缀 …
我知道static在C中是一个重载的关键字.在这里,我只关心它作为一个关键字用来强制内部链接.
如果在.c文件中声明了全局变量,则使用static和不使用之间有什么区别static?无论哪种方式,没有其他.c文件可以访问变量,因此该变量基本上是文件的"私有",有或没有static关键字.
例如,如果我有一个文件foo.c,并且我声明了一个全局变量:
int x = 5;
该变量x仅对内部代码可用foo.c(除非我在一些带有extern关键字的共享头文件中声明它).但是如果我没有在头文件中声明它,那么如果我输入的话会有什么不同:
static int x = 5.
无论哪种方式,它似乎x都有内部联系.所以我static对这方面的目的感到困惑.
显然,从§3.3.1/ 4开始,这个代码片段无法编译,因为它包含两个A在全局命名空间中具有相同名称的不同实体,extern int A;并且static int A = 101;.也就是说,一个有外部,另一个有内部联系.
#include <iostream>
extern int A;
static int A = 101;
class A{};
int main()
{
std::cout << A << '\n';
}
Run Code Online (Sandbox Code Playgroud)
那么为什么这个代码会编译?
#include <iostream>
static int A = 101;
extern int A;
class A{};
int main()
{
std::cout << A << '\n';
}
Run Code Online (Sandbox Code Playgroud)
编辑
我认为这个被认为是重复的问题的接受答案基本上说,在第二个片段中,变量A仍然有内部联系,尽管extern声明.但这与我在下面对@dyp的评论中提到的第3.5/4段不一致.
§3.5/ 4:
未命名的命名空间或在未命名的命名空间中直接或间接声明的命名空间具有内部链接.所有其他名称空间都有外部链接.具有名称空间作用域的名称上面没有给出内部链接,如果是名称,则具有与封闭名称空间相同的链接
- 一个变量; 要么
...
编辑1:
OP使用§3.5/ 6来证明他对另一个问题的回答.
§3.5/ 6(强调我的):
在块作用域中声明的函数的名称和由块作用域 extern声明声明的变量的名称具有链接.如果存在具有相同名称和类型的链接的实体的可见声明,忽略在最内部封闭命名空间范围之外 …
尝试使用 gcc 12.1.0 编译以下代码时出现链接时错误。使用 clang、msvc 和较旧的 gcc,它可以按预期进行编译。
template<typename T>
void def()
{}
template<void (*foobar)() = def<int>>
void bar()
{
foobar();
}
template<typename T>
void foo()
{
bar();
}
int main()
{
foo<int>();
}
Run Code Online (Sandbox Code Playgroud)
Error: /usr/bin/ld: /tmp/cchkaKVw.o: in function `void bar<&(void def<int>())>()':
> main.cpp:(.text._Z3barIXadL_Z3defIiEvvEEEvv[_Z3barIXadL_Z3defIiEvvEEEvv]+0x5): undefined reference to `void def<int>()'
Run Code Online (Sandbox Code Playgroud)
这是 gcc 回归还是这段代码有问题?