静态与外部“C”/“C”#x2B;“#x2B;”

发布于 2024-07-14 15:13:31 字数 448 浏览 9 评论 0原文

静态成员函数和外部“C”链接函数有什么区别? 例如,当在 C++ 中使用“makecontext”时,我需要传递一个函数指针。 Google 建议使用 extern“C” 链接,因为“makecontext”是 C。但我发现使用 static 也可以。 我只是幸运还是...

class X {
   public:
   static void proxy(int i) {}
}
makecontext(..., (void (*)(void)) X::proxy, ...);

vs

extern "C" void proxy(int i) {}
makecontext(..., (void (*)(void)) proxy, ...);

编辑:您能否展示静态成员版本不起作用的编译器或体系结构(并且这不是编译器中的错误)?

What is the difference between a static member function and an extern "C" linkage function ? For instance, when using "makecontext" in C++, I need to pass a pointer to function. Google recommends using extern "C" linkage for it, because "makecontext" is C. But I found out that using static works as well. Am I just lucky or...

class X {
   public:
   static void proxy(int i) {}
}
makecontext(..., (void (*)(void)) X::proxy, ...);

vs

extern "C" void proxy(int i) {}
makecontext(..., (void (*)(void)) proxy, ...);

EDIT: Can you show a compiler or architecture where the static member version does not work (and it's not a bug in the compiler) ?

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

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

发布评论

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

评论(5

最偏执的依靠 2024-07-21 15:13:31

是的,你只是幸运:) extern "C" 是每个 C++ 编译器都必须支持的 C 语言的一种语言链接,除了默认的 extern "C++" 之外。 编译器可能支持其他语言链接。 例如,GCC 支持 extern“Java”,它允许与 java 代码交互(尽管这相当麻烦)。

extern "C" 告诉编译器您的函数可由 C 代码调用。 这可以但不是必须包括适当的调用约定和适当的 C 语言名称修饰(有时称为“装饰”)以及其他内容,具体取决于实现。 如果您有一个静态成员函数,则它的调用约定是您的 C++ 编译器之一。 通常它们与该平台的 C 编译器相同 - 所以我说你只是幸运。 如果你有一个 C API 并且你传递了一个函数指针,最好总是将一个函数指针放入一个用 extern "C" 声明的函数中,就像

extern "C" void foo() { ... }

即使函数指针类型不包含链接规范,但看起来像

void(*)(void)

链接是一个不可分割的一部分类型 - 没有 typedef 就无法直接表达它:

extern "C" typedef void(*extern_c_funptr_t)();

Comeau C++ 编译器在严格模式下会发出错误,例如,如果您尝试将上面的 extern "C" 函数的地址分配给 (void(*)()),因为这是一个指向具有 C++ 链接的函数的指针。

Yes, you are just lucky :) The extern "C" is one language linkage for the C language that every C++ compiler has to support, beside extern "C++" which is the default. Compilers may supports other language linkages. GCC for example supports extern "Java" which allows interfacing with java code (though that's quite cumbersome).

extern "C" tells the compiler that your function is callable by C code. That can, but not must, include the appropriate calling convention and the appropriate C language name mangling (sometimes called "decoration") among other things depending on the implementation. If you have a static member function, the calling convention for it is the one of your C++ compiler. Often they are the same as for the C compiler of that platform - so i said you are just lucky. If you have a C API and you pass a function pointer, better always put one to a function declared with extern "C" like

extern "C" void foo() { ... }

Even though the function pointer type does not contain the linkage specification but rather looks like

void(*)(void)

The linkage is an integral part of the type - you just can't express it directly without a typedef:

extern "C" typedef void(*extern_c_funptr_t)();

The Comeau C++ compiler, in strict mode, will emit an error for example if you try to assign the address of the extern "C" function of above to a (void(*)()), beause this is a pointer to a function with C++ linkage.

生寂 2024-07-21 15:13:31

请注意,extern C 是 C/C++ 互操作性的推荐方式。 这里是大师在讲的。 添加到 eduffy 的答案:请注意,全局名称空间中的静态函数和变量已被弃用。 至少使用匿名名称空间。

回到 extern C:如果您不使用 extern C,您将必须知道确切的损坏名称并使用它。 那是更痛苦的事情。

Note, that extern C is the recommended way of C/C++ interoperability. Here is the master talking about it. To add to eduffy's answer: note that static functions and variables in the global namespace are deprecated. Use an anonymous namespace at least.

Back to extern C: if you don't use extern C you will have to know the exact mangled name and use it. That is much more of a pain.

全部不再 2024-07-21 15:13:31

extern "C" 禁用 C++ 编译器的名称修改(这是重载所必需的)。

如果您在 A.cpp 中将函数声明为 static,则 B.cpp 无法找到该函数(它是 C 的遗留物,与将函数放入匿名命名空间具有相同的效果) 。

extern "C" disables the C++ compiler's name mangling (which is required for overloading).

If you declare a function in A.cpp to be static, then it cannot be found by B.cpp (it's leftover from C, and it has the same effect of putting a function inside an anonymous namespace).

当梦初醒 2024-07-21 15:13:31

extern "C" 所做的大部分工作很大程度上取决于编译器。 许多平台根据声明更改名称修改和调用约定,但标准中没有指定这些。 事实上,该标准唯一要求的是块中的代码可以从 C 函数调用。 至于你的具体问题,标准说:

两种不同的函数类型
语言联系是不同的类型
即使它们在其他方面是相同的。

这意味着 extern "C" void proxy(int i) {}/*extern "C++"*/void proxy(int i) {} 具有不同的类型,并且因此,指向这些函数的指针也将具有不同的类型。 编译器不会使您的代码失败,就像它不会使一项伟大的工作失败一样,例如:

int *foo = (int*)50;
makecontext(..., (void (*)(void)) foo, ...);

此代码可能在某些平台上工作,但这并不意味着它可以在另一个平台上工作(即使编译器是完全符合标准)。 您正在利用特定平台的工作方式,如果您不关心编写可移植代码,这可能没问题。

至于静态成员函数,它们不需要有 this 指针,因此编译器可以自由地将它们视为非成员函数。 同样,这里的行为是特定于平台的。

Most of what extern "C" does is largely compiler dependant. Many platforms change the name mangling and calling convention based off the declaration, but none of that is specified by the standard. Really the only thing the standard requires is that the code in the block is callable from C functions. As for your specific question, the standard says:

Two function types with different
language linkages are distinct types
even if they are otherwise identical.

This means extern "C" void proxy(int i) {} and /*extern "C++"*/void proxy(int i) {} have different types, and as a result pointers to these functions would have different types as well. The compiler doesn't fail your code for the same reason it wouldn't fail a great piece of work like:

int *foo = (int*)50;
makecontext(..., (void (*)(void)) foo, ...);

This code might work on some platform, but that doesn't mean it will work on another platform (even if the compiler was fully standard compliant). You are taking advantage of how your particular platform works, which might be ok if you aren't concerned about writing portable code.

As for static member functions, they aren't required to have a this pointer so the compiler is free to treat them as a non member function. Again, the behavior here is platform specific.

花辞树 2024-07-21 15:13:31

一般来说

存储类别

存储类别用于指示变量或标识符的持续时间和范围。

持续时间:

持续时间表示变量的生命周期。

范围:

范围表示变量的可见性。

静态存储类:

静态存储类用于声明一个标识符,该标识符是函数或文件的局部变量,并且在控制从声明位置传递后存在并保留其值。 该存储类别具有永久的持续时间。 此类声明的变量从一次函数调用到下一次调用都保留其值。 范围是本地的。 变量仅由其在其中声明的函数知晓,或者如果在文件中全局声明,则仅由该文件内的函数知晓或可见。 该存储类保证变量的声明还将变量初始化为零或所有位关闭。

外部存储类

外部存储类用于声明一个全局变量,该变量将为文件中的函数所知,并且能够为程序中的所有函数所知。 该存储类别具有永久的持续时间。 此类的任何变量都保留其值,直到被另一个赋值更改为止。 范围是全球性的。 程序中的所有函数都可以知道或看到变量。

Generally speaking

Storage classes:

storage classes are used to indicate duration and scope of a variable or identifier.

Duration:

Duration indicates the life span of a variable.

Scope:

Scope indicates the visibility of the variable.

Static storage class:

The static storage class is used to declare an identifier that is a local variable either to a function or a file and that exists and retains its value after control passes from where it was declared. This storage class has a duration that is permanent. A variable declared of this class retains its value from one call of the function to the next. The scope is local. A variable is known only by the function it is declared within or if declared globally in a file, it is known or seen only by the functions within that file. This storage class guarantees that declaration of the variable also initializes the variable to zero or all bits off.

Extern storage class:

The extern storage class is used to declare a global variable that will be known to the functions in a file and capable of being known to all functions in a program. This storage class has a duration that is permanent. Any variable of this class retains its value until changed by another assignment. The scope is global. A variable can be known or seen by all functions within a program.

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