博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
杂注__declspec
阅读量:3958 次
发布时间:2019-05-24

本文共 4083 字,大约阅读时间需要 13 分钟。

今天看到一个一个好玩的东西:__declspec。这是Microsoft提供的一个关键词,配合一些属性可以对标准c++做一些扩充。(所以只能在Visual Studio上用)

总结一下其中我觉得有意思的。如有错漏还望指摘~

__declspec的用法是:__declspec(属性1 [, 属性2, … ])。

其中我学会了的有如下一些属性:

  1. deprecated

    这个属性可以修饰变量、函数、结构体、命名空间等等,用来标明这个名称或者实体,由于效率、安全或者其他原因已经被弃用。如果使用你程序的人调用了这个名称或者实体,编译时就会报错(warning),必须使用#pragma warning来关闭该警告。这是出于兼容性考虑的,如果调用你程序的人由于某种原因暂时不能更改接口,那么保留原接口就可以使得他可以继续调用而不会出错。但是出于安全或者效率角度必须进行一定的提醒。
    使用方法:

    __descspec(deprecated) int test1;__descspec(deprecated("This function is deprecated for some reason!")) void test2(void);struct [[deprecated]] test3;namespace [[deprecated("This name space is deprecated for some reason!")]] test4;#pragma deprecated(test2);

    当调用已弃置的名称或实体时,就会出现这样的警告:

    调用已弃置名称或实体时提示警告
    如果自定义了提示字符串,如上面的test2函数和test4命名空间,那么上图的说明部分就会显示自定义的提示字符串。
    注意:

    1. 前四种使用方式都会出现4996警告,最后一种#pragma的方式则会出现4995警告;
    2. 如果使用第三种或者第四种,一定是两个中括号。这种使用方式是C++自带的属性,因此各个编译器都可以识别;
    3. 声明和定义任意一个被修饰为已弃置,那么这个名字或实体就会被声明为已弃置。

    如果仍然想要使用已被弃置的名称或者实体,就需要使用:

    #pragma warning(disable: 4996)

    来关闭这些警告。(如果是最后一种,则需要关掉4995警告)

  2. noretern

    这个属性我看了半天,官方解释是:

    指示函数不返回。

    此属性仅应用到函数声明中正在声明的函数名。若拥有此属性的函数实际上返回,则行为未定义。
    若函数的任何声明指定此属性,则其首个声明必须指定它。若函数在一个翻译单元中声明为带 [[noreturn]] 属性,而同一函数在另一翻译单元中声明为不带 [[noreturn]] 属性,则程序非良构;不要求诊断。

    我:???感觉自己就是个菜鸡.jpg。为什么每个字都认识,连在一起就不知道在说什么???

    直到我看到一个评论:

    这个属性就是标明那些一定会把程序干掉的函数。23333333

    使用方法:

    __declspec(noreturn) void end(int x){
    exit(x);}[[noreturn]] void end2(int x){
    exit(x); }

    注意:正如官方解释所说,如果一个函数被声明了noreturn属性,那么在整个程序中对这个函数的第一次声明中必须指定noreturn属性。

  3. property

    这个属性非常有趣,他可以把函数伪装成变量
    这个属性的名字就叫做属性。所谓属性,就是类或者结构体里,表面上看上去像一个成员变量的东西。
    先来介绍使用方法:

    __declspec(property(get = getFunc, put = setFunc)) type x[]; //这里可以是x,x[], x[][], ...

    然后再来说明,什么叫把函数伪装成变量呢?比如如下这样一个计算Fibonacci数列的非常简单的类:

    class Fibonacci{
    public: int getN(int x){
    if(x <= 0) return -1; if(x == 1 || x == 2) return 1; int i = 1, j = 1, tmp; for(int l = 2; l < x; l++){
    tmp = i + j; i = j; j = tmp; } return j; } __declspec(property(get = getN)) int f[];}int main(){
    Fibonacci x; cout << x.f[6] << endl; //8}

    当调用Fibonacci中的f[6]时,输出了8。就好像类里真的有这样一个数组一样。然而实际上却是根据输入进行计算得出来的。这就是将函数伪装成一个变量。

    这个属性构造了一个虚拟的变量,然而实际上却将这个变量指向了两个函数。当这个变量为左值时,调用put指向的函数,并将每一个括号里的值以及右值依次作为参数传入函数;当变量为右值时,就调用get指向的函数,并将每一个括号里的值依次传入函数。
    值得注意的是

    1. 这里是在调用时就进行了转换。也就是说,如上面的代码,如果将getN函数变成private的,那么将会调用失败。只有当函数和属性同时是public的时候,外界才能正常调用。
    2. 可以重复定义,但是以第一次定义为准,之后的定义不会报错,但是无效。
    3. 函数可以重载,但是因为是将函数伪装成了变量,而变量只有固定的类型,所以要求所有的重载函数返回值必须相同,与设定的虚拟变量的类型一致。

    再举一个简单的例子来说明这个属性的使用:

    class test{
    private: unordered_map
    map;public: int getM(int key){
    auto it = map.find(key); if(it == map.end()) return -1; else return it->second; } void insertM(int key, int value){
    map[key] = value; } __declspec(property(get = getM, put = insertM)) int x[];}

    这里就将字典map伪装成了数组x;

  4. novtable

    这个属性是用来修饰类或者结构。作用是,禁止构造虚函数指针表。因此当类或结构中含有虚函数时,将禁止类或结构的实例化。是用来指定接口类的。
    使用方法:

    __declspec(novtable) class Interface{
    virtual void func1(int x); virtual void func2(double y);}

    此时Interface类只能作为接口类,不能被实例化。其中的虚函数也相当于纯虚函数。

  5. noinline

    这个属性用来指定函数为非内联函数。用于类内声明的函数。我们知道,如果函数在类内定义,一般会默认为内联函数,这时用这个属性可以取消其内联属性。如:

    class test{
    public: __declspec(noinline) void print(int x){
    cout << x << endl; }}

    此时print函数虽然在类内进行了定义,也足够简单,但强制其为非内联函数。

  6. dllimportdllexport

  7. naked

    这个属性是用来修饰函数的,标明编译的时候不再生成用来现场保护的prolog和epilog,用于想在程序内用内联汇编自定义prolog和epilog的情况。值得注意的是:

    1. 这个属性只在ARM和x86下生效,在x64下不提供该属性
    2. naked修饰的函数不能是内联函数

    使用方式:

    __declspec(naked) void func1(const char* str) {
    __asm {
    /* prolog */ push ebp mov ebp, esp sub esp, __LOCAL_SIZE } printf("%s\n", str); __asm {
    /* epilog */ mov esp, ebp pop ebp ret }}
  8. allocate

    allocate属性修饰变量,指定在编译成汇编语言时,变量存储在什么字段。
    使用方法:

    #pragma section("mycode",read,write)__declspec(allocate("mycode")) int x = 0;
  9. selectany

    我们知道,在头文件中定义全局变量会引发错误,这是由于如果多次引用头文件,就会导致全局变量的多次定义。而selectany属性则可以避免这种错误,告诉编译器挑一个就行。
    使用方法:

    //test.h__declspec(selectany) int x = 0;//test2.h#include "test.h"//main.cpp#include "test.h"#include "test2.h"//这里不用selectany属性就会报错

转载地址:http://ktxzi.baihongyu.com/

你可能感兴趣的文章
inno使用教程
查看>>
网吧系统母盘制作(系统分区整体考虑优化配置篇)
查看>>
spring beans beanfactory applicationcontext
查看>>
使用ORM工具进行数据访问
查看>>
使用ORM工具进行数据访问
查看>>
Quartz 使用手记 --转
查看>>
编译与部署Eclipse+Tomcat+MySQL+Liferay4.1.2
查看>>
MySQL用户授权
查看>>
mysql忘记密码怎么办?~
查看>>
MySQL修改密码方法总结
查看>>
怎么将我的硬盘屏蔽
查看>>
关于MySQL select into 和 SQLServer select into
查看>>
2003应用
查看>>
文件上传组件比较
查看>>
关于MySQL select into 和 SQLServer select into
查看>>
搭建开发环境(初学liferay必看)
查看>>
Apache FileUpload文件上传组件API解析
查看>>
屏蔽usb的方法- -
查看>>
JSP编程进度条设计
查看>>
精心收集的面试笔试题库,网络上很难找到这么齐全的,推荐给大家
查看>>