QT源码学习 | 编译器知识点

简介: 本文是关于QT源码学习中编译器知识点的总结,包括`__declspec`、`Q_FUNC_INFO`、`__assume`、`__attribute__`、`__ASSEMBLER__`、`QT_SUPPORTS`和`QT_WARNING_DISABLE_MSVC`等宏定义的使用和作用,以及相关参考链接。

一 知识点来源

C:\Qt\5.15.2\msvc2019_64\include\QtCore\qcompilerdetection.h

C:\Qt\5.15.2\msvc2019_64\include\QtCore\qglobal.h

二 知识点

1 __declspec

__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。其它的有关存储方式的修饰符如static与extern等是C和 C++语言的ANSI规范,而__declspec是一种扩展属性的定义。扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。

1.__declspec关键字应该出现在简单声明的前面。对于出现在*或&后面或者变量声明中标识符的前面的__declspec,编译器将忽略并且不给出警告。
2.要注意区分__declspec是修饰类型还是修饰变量:
__declspec(align(8)) struct Str b;修饰的是变量b。其它地方定义的struct Str类型的变量将不受__declspec(align(8))影响。
__declspec(align(8)) struct Str {};修饰的是struct Str类型。所有该类型的变量都受__declspec(align(8))影响。

dllimport,dllexport
格式:
__declspec( dllimport ) declarator
__declspec( dllexport ) declarator
分别用来从dll导入函数,数据,或对象以及从dll中导出函数,数据,或对象。相当于定义了dll的接口,为它的客户exe或dll定义可使用的函数,数据,或对象。
将函数声明成dllexport就可以免去定义模块定义(.DEF)文件。
dllexport代替了__export关键字。
被声明为dllexport的C++函数导出时的函数名将会按照C++规则经过处理。如果要求不按照C++规则进行名字处理,请使用.def文件或使用extern "C"。

noreturn
一个函数被__declspec(noreturn)所修饰,那么它的含义是告诉编译器,这个函数不会返回,其结果是让编译器知道被修饰为__declspec(noreturn)的函数之后的代码不可到达。
如果编译器发现一个函数有无返回值的代码分支,编译器将会报C4715警告,或者C2202错误信息。如果这个代码分支是因为函数不会返回从而无法到达的话,可以使用约定__declspec(noreturn)来避免上述警告或者错误。
将一个期望返回的函数约定为__declspec(noreturn)将导致未定义的行为。
在下面的这个例子中,main函数没有从else分支返回,所以约定函数fatal为__declspec(noreturn)来避免编译或警告信息。
__declspec(noreturn) extern void fatal () {}
int main() {
if(1)
return 1;
else if(0)
return 0;
else
fatal();
}

/* Symantec C++ is now Digital Mars */
#if defined(__DMC__) || defined(__SC__)
#  define Q_CC_SYM
/* "explicit" semantics implemented in 8.1e but keyword recognized since 7.5 */
#  if defined(__SC__) && __SC__ < 0x750
#    error "Compiler not supported"
#  endif

#elif defined(_MSC_VER)
#  ifdef __clang__
#    define Q_CC_CLANG ((__clang_major__ * 100) + __clang_minor__)
#  endif
#  define Q_CC_MSVC (_MSC_VER)
#  define Q_CC_MSVC_NET
#  define Q_OUTOFLINE_TEMPLATE inline
#  define Q_COMPILER_MANGLES_RETURN_TYPE
#  define Q_FUNC_INFO __FUNCSIG__
#  define Q_ALIGNOF(type) __alignof(type)
#  define Q_DECL_ALIGN(n) __declspec(align(n))
#  define Q_ASSUME_IMPL(expr) __assume(expr)
#  define Q_UNREACHABLE_IMPL() __assume(0)
#  define Q_NORETURN __declspec(noreturn)
#  define Q_DECL_DEPRECATED __declspec(deprecated)
#  ifndef Q_CC_CLANG
#    define Q_DECL_DEPRECATED_X(text) __declspec(deprecated(text))
#  endif
#  define Q_DECL_EXPORT __declspec(dllexport)
#  define Q_DECL_IMPORT __declspec(dllimport)
#  define QT_MAKE_UNCHECKED_ARRAY_ITERATOR(x) stdext::make_unchecked_array_iterator(x) // Since _MSC_VER >= 1800
#  define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) stdext::make_checked_array_iterator(x, size_t(N)) // Since _MSC_VER >= 1500
/* Intel C++ disguising as Visual C++: the `using' keyword avoids warnings */
#  if defined(__INTEL_COMPILER)
#    define Q_DECL_VARIABLE_DEPRECATED
#    define Q_CC_INTEL  __INTEL_COMPILER
#  endif

2 # define Q_FUNC_INFO __FUNCSIG__

__FUNCTION__ 特性最初是为C语言设计的,然而,C++程序员也会经常需要有关他们函数的额外信息,在Visual Studio 2005中,还支持另外两种非标准的扩展特性:__FUNCDNAME__ 与 __FUNCSIG__ ,其分别转译为一个函数的修饰名与签名。

例子
int test(int x)
vs2010
__FUNCTION__:test
__FUNCDNAME__:?test@@YAHH@Z
__FUNCSIG__:int __cdecl test(int)
gcc
__FUNCTION__:test
__func__:test

3 __assume

Microsoft 专用

传递优化程序提示。

#  define Q_ASSUME_IMPL(expr) __assume(expr)
#  define Q_UNREACHABLE_IMPL() __assume(0)
// compiler_intrinsics__assume.cpp
#ifdef DEBUG
# define ASSERT(e)    ( ((e) || assert(__FILE__, __LINE__) )
#else
# define ASSERT(e)    ( __assume(e) )
#endif

void func1(int i)
{
   
}

int main(int p)
{
   
   switch(p){
   
      case 1:
         func1(1);
         break;
      case 2:
         func1(-1);
         break;
      default:
         __assume(0);
            // This tells the optimizer that the default
            // cannot be reached. As so, it does not have to generate
            // the extra code to check that 'p' has a value
            // not represented by a case arm. This makes the switch
            // run faster.
   }
}

4 __attribute__

GNU C 的一大特色就是__attribute__ 机制。__attribute__ 可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute )。

__attribute__ 书写特征是:__attribute__ 前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__ 参数。

__attribute__ 语法格式为:__attribute__ ((attribute-list))

关键字__attribute__ 也可以对结构体(struct )或共用体(union )进行属性设置。大致有六个参数值可以被设定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias 。

在使用__attribute__ 参数时,你也可以在参数的前后都加上“__” (两个下划线),例如,使用__aligned__而不是aligned ,这样,你就可以在相应的头文件里使用它而不用关心头文件里是否有重名的宏定义。

在TC下:struct my{
    char ch; int a;}      sizeof(int)=2;sizeof(my)=3;(紧凑模式)

在GCC下:struct my{
    char ch; int a;}     sizeof(int)=4;sizeof(my)=8;(非紧凑模式)

在GCC下:struct my{
    char ch; int a;}__attrubte__ ((packed))        sizeof(int)=4;sizeof(my)=5

5 __ASSEMBLER__

#ifndef __ASSEMBLER__
#  include <assert.h>
#  include <stddef.h>
#endif

当预处理汇编语言,置为1

6 # define QT_SUPPORTS(FEATURE) (!defined QT_NO_##FEATURE)

define 中的# ## 一般是用来拼接字符串的,但是实际使用过程中,有哪些细微的差别呢,我们通过几个例子来看看。

是字符串化的意思,出现在宏定义中的#是把跟在后面的参数转成一个字符串;

eg:

define strcpy__(dst, src) strcpy(dst, #src)

strcpy__(buff,abc) 相当于 strcpy__(buff,“abc”)

是连接符号,把参数连接在一起

define FUN(arg) my##arg

则 FUN(ABC)

等价于 myABC

7 # define QT_WARNING_DISABLE_MSVC(number) __pragma(warning(disable: number))

下面的注释很搞笑,stupid compilers


/*
   Avoid some particularly useless warnings from some stupid compilers.
   To get ALL C++ compiler warnings, define QT_CC_WARNINGS or comment out
   the line "#define QT_NO_WARNINGS".
*/
#if !defined(QT_CC_WARNINGS)
#  define QT_NO_WARNINGS
#endif
#if defined(QT_NO_WARNINGS)
#  if defined(Q_CC_MSVC)
QT_WARNING_DISABLE_MSVC(4251) /* class 'type' needs to have dll-interface to be used by clients of class 'type2' */
QT_WARNING_DISABLE_MSVC(4244) /* conversion from 'type1' to 'type2', possible loss of data */
QT_WARNING_DISABLE_MSVC(4275) /* non - DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' */
QT_WARNING_DISABLE_MSVC(4514) /* unreferenced inline function has been removed */
QT_WARNING_DISABLE_MSVC(4800) /* 'type' : forcing value to bool 'true' or 'false' (performance warning) */
QT_WARNING_DISABLE_MSVC(4097) /* typedef-name 'identifier1' used as synonym for class-name 'identifier2' */
QT_WARNING_DISABLE_MSVC(4706) /* assignment within conditional expression */
QT_WARNING_DISABLE_MSVC(4355) /* 'this' : used in base member initializer list */
QT_WARNING_DISABLE_MSVC(4710) /* function not inlined */
QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc */
#  elif defined(Q_CC_BOR)
#    pragma option -w-inl
#    pragma option -w-aus
#    pragma warn -inl
#    pragma warn -pia
#    pragma warn -ccc
#    pragma warn -rch
#    pragma warn -sig
#  endif
#endif

编译器还支持特定于 __pragma Microsoft 的关键字,该关键字的功能与 #pragma 指令相同。 区别在于, __pragma 关键字在宏定义中可内联使用。 指令 #pragma 在宏定义中不可用,因为编译器将指令中的数字符号字符 ('#') 解释为 字符串化运算符 (#)

三 参考链接

(4条消息) __declspec用法详解_章志强的博客-CSDN博客___declspec

(4条消息) __declspec(dllexport)和__declspec(dllimport)_pinganyehandan的博客-CSDN博客

__FUNCSIG__ __FUNCDNAME__ __FUNCTION__ __func__ - 八叶草 - C++博客 (cppblog.com)

Clang Language Extensions — Clang 15.0.0git documentation (llvm.org)

SD-FeatureTest: Feature-Test Macros and Policies : Standard C++ (isocpp.org)

__assume | Microsoft Docs

(4条消息) C语言__attribute__的使用_【ql君】qlexcel的博客-CSDN博客___attribute__

宏定义 - 知乎 (zhihu.com)

C++/C 宏定义(define)中# ## 的含义 宏拼接 - sz123 - 博客园 (cnblogs.com)

Pragma 指令和 __pragma 和 _Pragma 关键字 | Microsoft Docs

相关文章
|
编译器
Qt获取当前所用的Qt版本、编译器、位数等信息
Qt获取当前所用的Qt版本、编译器、位数等信息
|
6月前
|
存储 编译器 C++
【Qt 元对象系统 02】深入探索Qt的元对象编译器:从原理到实践
【Qt 元对象系统 02】深入探索Qt的元对象编译器:从原理到实践
410 0
|
编译器 C语言 Windows
Qt 使用MinGW编译器调用MinGW编译生成的dll
Qt 使用MinGW编译器调用MinGW编译生成的dll
314 0
|
程序员 C++ Windows
Qt多线程分享——你必须知道的进程知识点
Qt多线程分享——你必须知道的进程知识点
|
编译器 计算机视觉
关于 Qt编译时使用msvc编译器报错“Error: cannot open ...main.obj.10836.32.jom for write” 的解决方法
关于 Qt编译时使用msvc编译器报错“Error: cannot open ...main.obj.10836.32.jom for write” 的解决方法
关于 Qt编译时使用msvc编译器报错“Error: cannot open ...main.obj.10836.32.jom for write” 的解决方法
|
编译器 C语言 Windows
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(三)
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(三)
164 0
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(三)
|
编译器 C语言 Windows
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(二)
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(二)
139 0
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(二)
|
编译器 Linux C语言
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(一)
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(一)
405 0
【C 语言】Windows 下使用 gcc 编译器 ( 常用的编译器 | Qt 中的 gcc 编译器 | 独立安装 MinGW )(一)
|
编译器 C语言
QT软件开发:QtCreator使用VS2017编译器中文乱码解决
QT软件开发:QtCreator使用VS2017编译器中文乱码解决
400 0
QT软件开发:QtCreator使用VS2017编译器中文乱码解决
|
编译器 C语言 计算机视觉
QT5在windows下调用OpenCV库出现: undefined reference to `xxxxx&#39; 错误解决办法(适用MinGW编译器)。
QT5在windows下调用OpenCV库出现: undefined reference to `xxxxx&#39; 错误解决办法(适用MinGW编译器)。
1672 0
QT5在windows下调用OpenCV库出现: undefined reference to `xxxxx&#39; 错误解决办法(适用MinGW编译器)。