msdn随笔笔记(四)-extern;Linkage Specifications;Linkage;CCriticalSection

本文详细介绍了C++中的extern关键字如何指定外部链接,以及Linkage规范的作用,包括C++中如何使用extern "C"进行跨语言链接。同时,文章提及了CCriticalSection在多线程中的应用,用于保护资源的独占访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Using extern to Specify Linkage

Syntax
linkage-specification :
extern declarator
extern string-literal { declaration-listopt }
extern string-literal declaration
declaration-list :
declaration
declaration-list declaration
The extern keyword declares a variable or function and specifies that it has external linkage (its name is visible from files other than the one in which it's defined). When modifying a variable, extern specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends). The variable or function may be defined in another source file, or later in the same file. Declarations of variables and functions at file scope are external by default.
For example:
int i = 1;
void other( void );
void main(){
  /* Reference to i, defined above: */
  extern int i;
  return;
}
void other( void ){
/* Address of global i assigned to pointer variable: */
  static int *external_i = &i;
/* i is redefined; global i no longer visible: */
  int i = 16;
In C++, when used with a string, extern specifies that the linkage conventions of another language are being used for the declarator(s). C functions and data can be accessed only if they are previously declared as having C linkage. However, they must be defined in a separately compiled translation unit.
Microsoft C++ supports the strings "C" and "C++" in the string-literal field. All of the standard include files use the extern "C" syntax to allow the run-time library functions to be used in C++ programs.
The following example shows alternative ways to declare names that have C linkage:
// Declare printf with C linkage.
extern "C" int printf( const char *fmt, ... );

//  Cause everything in the header file "cinclude.h"
//   to have C linkage.
extern "C"
{
#include <cinclude.h>
}

//  Declare the two functions ShowChar and GetChar
//   with C linkage.
extern "C"
{
    char ShowChar( char ch );
    char GetChar( void );
}

//  Define the two functions ShowChar and GetChar
//   with C linkage.
extern "C" char ShowChar( char ch )
{
    putchar( ch );
    return ch;
}

extern "C" char GetChar( void )
{
    char ch;

    ch = getchar();
    return ch;
}

// Declare a global variable, errno, with C linkage.
extern "C" int errno;

2.Linkage Specifications

The term “linkage specification” refers to the protocol for linking functions (or procedures) written in different languages. The following calling conventions are affected:

  • Case sensitivity of names.
  • Decoration of names. In C, the compiler prefixes names with an underscore. This is often called “decoration.” In C++, name decoration is used to retain type information through the linkage phase.
  • Order in which arguments are expected on the stack.
  • Responsibility for adjusting the stack on function return. Either the called function or the calling function is responsible.
  • Passing of hidden arguments (whether any hidden arguments are passed).

Syntax

linkage-specification :
extern string-literal { declaration-list opt }
extern string-literal declaration
declaration-list :
declaration
declaration-list

Linkage specification facilitates gradually porting C code to C++ by allowing the use of existing code.

Microsoft Specific

The only linkage specifications currently supported by Microsoft C++ are "C" and "C++".

END Microsoft Specific

The following example declares the functions atoi and atol with C linkage:

extern "C"
{
    int  atoi( char *string );
    long atol( char *string );
}

Calls to these functions are made using C linkage. The same result could be achieved with these two declarations:

extern "C" int  atoi( char *string );
extern "C" long atol( char *string );

Microsoft Specific

All Microsoft C standard include files use conditional compilation directives to detect C++ compilation. When a C++ compilation is detected, the prototypes are enclosed in an extern "C" directive as follows:

// Sample.h
#if defined(__cplusplus)
extern "C"
{
#endif

// Function declarations

#if defined(__cplusplus)
}
#endif 

END Microsoft Specific

You do not need to declare the functions in the standard include files as extern "C".

If a function is overloaded, no more than one of the functions of the same name can have a linkage specifier. (For more information, see Function Overloading in Chapter 7.)

Table 6.3 shows how various linkage specifications work.

Table 6.3   Effects of Linkage Specifications

SpecificationEffect
On an objectAffects linkage of that object only
On a functionAffects linkage of that function and all functions or objects declared within it
On a classAffects linkage of all nonmember functions and objects declared within the class

If a function has more than one linkage specification, they must agree; it is an error to declare functions as having both C and C++ linkage. Furthermore, if two declarations for a function occur in a program — one with a linkage specification and one without — the declaration with the linkage specification must be first. Any redundant declarations of functions that already have linkage specification are given the linkage specified in the first declaration. For example:

extern "C" int CFunc1();
...
int CFunc1();            // Redeclaration is benign; C linkage is
                         //  retained.

int CFunc2();
...
extern "C" int CFunc2(); // Error: not the first declaration of
                         //  CFunc2;  cannot contain linkage
                         //  specifier.

Functions and objects explicitly declared as static within the body of a compound linkage specifier ({ }) are treated as static functions or objects; the linkage specifier is ignored. Other functions and objects behave as if declared using the extern keyword. (See Using extern to Specify Linkage for details about the extern keyword.)

3.Linkage

Identifier names can refer to different identifiers in different scopes. An identifier declared in different scopes or in the same scope more than once can be made to refer to the same identifier or function by a process called “linkage.” Linkage determines the portions of the program in which an identifier can be referenced (its “visibility”). There are three kinds of linkage: internal, external, and no linkage.

4.CCriticalSection

A CCriticalSection object represents a critical section, which is a synchronization object that allows one thread at a time to access a resource or section of code. Critical sections are useful when only one thread at a time can be allowed to modify data or some other controlled resource. For example, adding nodes to a linked list is a process that should only be allowed by one thread at a time. By using a CCriticalSection object to control the linked list, only one thread at a time can gain access to the list.

The functionality of the CCriticalSection class is provided by an actual Windows CE CRITICAL_SECTION object.

Critical sections are used instead of mutexes when speed is critical and the resource will not be used across process boundaries. For more information on mutexes, see CMutex.

There are two methods for using a CCriticalSection object: stand-alone or embedded in a class.

To use a stand-alone CCriticalSection object, construct the CCriticalSection object when it is needed. After a successful return from the constructor, explicitly lock the object with a call to Lock. Call Unlock when you finish accessing the critical section. This method, while clearer to someone reading your source code, is more prone to error because you must remember to lock and unlock the critical section before and after access.

You can also share a class with multiple threads by adding a CCriticalSection-type data member to the class and locking the data member when needed.


### C++ 子对象链接警告 [-Wsubobject-linkage] 的原因 子对象链接警告 `[-Wsubobject-linkage]` 是由 GCC 或 Clang 编译器发出的一种警告,通常发生在类的静态成员变量或嵌套类型的定义与其声明不一致的情况下。这种警告表明程序可能依赖于未明确定义的行为,可能导致不可预测的结果。 当编译器检测到某个类的子对象(如嵌套类或静态数据成员)具有外部链接性时,如果这些子对象在不同的翻译单元中有不同的定义,则会触发此警告。这通常是由于头文件中的重复定义或条件编译引起的[^1]。 --- ### 解决方法 #### 方法一:确保一致性 通过检查并统一所有涉及该类及其子对象的定义和声明,可以消除此类警告。具体来说: - **避免多重定义** 如果某些静态成员或嵌套类型被多次定义,应将其移到实现文件中,或者仅保留单一定义。 - **使用 inline 关键字** 对于静态常量成员或函数,可以通过添加 `inline` 来显式指定其内联属性,从而避免链接冲突。例如: ```cpp class MyClass { static constexpr int value = 42; // 使用 constexpr 和 inline 隐式处理 }; ``` #### 方法二:禁用特定警告 如果确认警告不会影响程序行为,可以选择关闭 `-Wsubobject-linkage` 警告。对于 Clang 编译器,可以在编译选项中加入以下标志来抑制该警告: ```bash -Wno-subobject-linkage ``` 需要注意的是,这种方法只是隐藏了警告,并未真正解决问题,因此建议谨慎使用。 #### 方法三:重构代码结构 有时,复杂的继承关系或过多的嵌套类型可能会引发此类警告。重新设计类层次结构,减少不必要的嵌套定义,有助于从根本上解决问题。例如,将嵌套类移至顶层命名空间下: ```cpp // 原始定义 class Outer { struct Inner {}; }; // 修改后的定义 struct Inner {}; class Outer {}; ``` --- ### 示例代码修正 假设存在以下代码片段引发了 `[-Wsubobject-linkage]` 警告: ```cpp class Example { public: static const int VALUE; }; const int Example::VALUE = 42; // 可能因多处定义而触发警告 ``` 可以通过以下方式修复: ```cpp class Example { public: static constexpr int VALUE = 42; // 使用 constexpr 定义并内联化 }; ``` 或者,在多个源文件中共享同一定义时,可改为: ```cpp namespace constants { extern const int EXAMPLE_VALUE; } // 在 cpp 文件中定义 const int constants::EXAMPLE_VALUE = 42; ``` --- ### 总结 `[-Wsubobject-linkage]` 提醒开发者注意潜在的链接问题,尤其是在跨模块开发场景中。通过确保定义的一致性、合理使用 `inline` 或重构代码结构,能够有效解决这一问题。若确实无法修改代码逻辑,也可以考虑临时屏蔽该警告。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值