IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 手把手写C++服务器(13):C++11新特性之静态断言static_assert -> 正文阅读

[C++知识库]手把手写C++服务器(13):C++11新特性之静态断言static_assert

前言:我们学过很多断言,动态断言、零宽断言等等,这些在我之前的blog里都有总结。静态断言是C++11中的新技术,在服务端编程中经常使用,这里做一个学习总结。

目录

语法

优点

示例

参考

语法

static_assert(常量表达式,提示字符串)

如果第一个参数常量表达式的值为真(true或者非零值),那么static_assert不做任何事情,就像它不存在一样,否则会产生一条编译错误,错误位置就是该static_assert语句所在行,错误提示就是第二个参数提示字符串。

因为static_assert是编译过程中可计算的表达式,所以不能使用变量等,这样会造成编译报错。例如:

int func(int n) {
    static_assert(n < 0, "n is over 0");
    return 0;
}

因此,static_assert经常用于在代码的开头,预处理代码之后,用于检查一些编译支持错误、检查模板参数等。例如在编译前检查机器的位数是否是64位:

//该static_assert用来确保编译仅在32位的平台上进行,不支持64位的平台
//该语句可放在文件的开头处,这样可以尽早检查,以节省失败情况下耗费的编译时间
static_assert(sizeof(int) == 4, "64-bit code generation is not supported.");

优点

1、由于static_assert是编译期间断言,不生成目标代码,因此static_assert不会造成任何运行期性能损失

2、使用static_assert,可以在编译期发现更多的错误,用编译器来强制保证一些契约,帮助我们改善编译信息的可读性,尤其是用于模板时。

3、static_assert可以用在全局作用域中,命名空间中,类作用域中,函数作用域中,几乎可以不受限制的使用。

示例

在网络编程中,不同平台上消息类型长度可能不一样,而我们进行消息通信的时候,会检查消息长度(参考UDP/TCP保证可靠性问题),此时如果平台的标度不统一,就会造成验证消息长度失败,连接往往建立失败。因此在编译期间,检查消息类型的长度,如果失败直接退出,使用static_assert抛出异常。

这是一个roundtrip轮转的demo,使用UDP测量两个机器之间网络的延迟,static_assert在19行。具体的业务逻辑会在下一讲详细分析。

#include "InetAddress.h"
#include "Socket.h"

#include <thread>

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

const int g_port = 3123;

struct Message
{
  int64_t request;
  int64_t response;
} __attribute__ ((__packed__));

static_assert(sizeof(Message) == 16, "Message size should be 16 bytes");

int64_t now()
{
  struct timeval tv = { 0, 0 };
  gettimeofday(&tv, NULL);
  return tv.tv_sec * int64_t(1000000) + tv.tv_usec;
}

void runServer()
{
  Socket sock(Socket::createUDP());
  sock.bindOrDie(InetAddress(g_port));
  sock.bindOrDie(InetAddress(g_port));

  while (true)
  {
    Message message = { 0, 0 };

    struct sockaddr peerAddr;
    bzero(&peerAddr, sizeof peerAddr);
    socklen_t addrLen = sizeof peerAddr;
    ssize_t nr = ::recvfrom(sock.fd(), &message, sizeof message, 0, &peerAddr, &addrLen);
    if (nr == sizeof message)
    {
      message.response = now();
      ssize_t nw = ::sendto(sock.fd(), &message, sizeof message, 0, &peerAddr, addrLen);
      if (nw < 0)
      {
        perror("send Message");
      }
      else if (nw != sizeof message)
      {
        printf("sent message of %zd bytes, expect %zd bytes.\n", nw, sizeof message);
      }
    }
    else if (nr < 0)
    {
      perror("recv Message");
    }
    else
    {
      printf("received message of %zd bytes, expect %zd bytes.\n", nr, sizeof message);
    }
  }
}

void runClient(const char* server_hostname)
{
  Socket sock(Socket::createUDP());
  InetAddress serverAddr(g_port);
  if (!InetAddress::resolve(server_hostname, &serverAddr))
  {
    printf("Unable to resolve %s\n", server_hostname);
    return;
  }

  if (sock.connect(serverAddr) != 0)
  {
    perror("connect to server");
    return;
  }

  std::thread thr([&sock] () {
    while (true)
    {
      Message message = { 0, 0 };
      message.request = now();
      int nw = sock.write(&message, sizeof message);
      if (nw < 0)
      {
        perror("send Message");
      }
      else if (nw != sizeof message)
      {
        printf("sent message of %d bytes, expect %zd bytes.\n", nw, sizeof message);
      }

      ::usleep(200*1000);
    }
  });

  while (true)
  {
    Message message = { 0, 0 };
    int nr = sock.read(&message, sizeof message);
    if (nr == sizeof message)
    {
      int64_t back = now();
      int64_t mine = (back + message.request) / 2;
      printf("now %jd round trip %jd clock error %jd\n",
             back, back - message.request, message.response - mine);
    }
    else if (nr < 0)
    {
      perror("send Message");
    }
    else
    {
      printf("received message of %d bytes, expect %zd bytes.\n", nr, sizeof message);
    }
  }
}

int main(int argc, const char* argv[])
{
  if (argc < 2)
  {
    printf("Usage:\nServer: %s -s\nClient: %s server_hostname\n", argv[0], argv[0]);
    return 0;
  }

  if (strcmp(argv[1], "-s") == 0)
  {
    runServer();
  }
  else
  {
    runClient(argv[1]);
  }
}

参考

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-06 23:57:47  更:2021-07-06 23:58:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 1:36:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码