C/C++宏编程

2023-11-13

C/C++宏编程

宏的复杂使用,永远不要写两次!

介绍

我读过的所有C/C++教科书都批评宏的使用。“不要使用它们,它们很危险,因为它们隐藏了你实际写的东西。尤其是看起来很实用的宏。有些人甚至说,没有理由在C++的模板类的发明中使用宏。

尽管如此,宏仍然在某些地方使用。

例如,调试宏,如 、 等。它们都是看起来函数的宏,在调试和发布版本下扩展到不同的东西。ASSERTVERIFYTRACE

我知道有些人从不使用这些宏。相反,它们只是使用在调试和发布版本中以不同方式实现的函数。为什么?因为他们害怕使用看起来很函数的宏的威胁。也就是说,他们希望始终计算内部表达式,即使在不使用其值的发布版本中也是如此。好吧,这对某些人来说可能是合理的。事实上,将一些重要的代码放在里面(而不是)是一个非常常见的错误。ASSERTASSERTVERIFY

我个人总是使用这些的宏版本。那是因为我非常频繁地使用调试宏来在出现问题时立即获得指示,而另一方面,我不希望最终的可执行文件附带所有这些废话。

另一个广泛使用的宏的例子与ANSI/Unicode有关。这包括 ()、所有类似宏的宏。此外,Windows API 具有许多带有 或 后缀的函数,例如 、.也就是说,实际上是一个宏,它根据构建设置扩展到其中一个宏。_T_tprintfAWGetMessageAGetMessageWGetMessage

尽管受到批评,但宏仍在使用。有人可能会争论这是否合理,但这不是本文的主题。我想在本文中展示通过复杂使用宏可以完成的非常令人惊奇的事情。是否使用这些技术 - 决定取决于您。

通信协议示例

假设您必须实现一些通信协议。该协议由不同类型的“消息”组成,每条消息都有其特定的参数。

让我们同意(现在)每个传输的消息都从其 4 字节大小开始(从而将最大的消息限制为 4GB 的数量级),然后是它的 2 字节代码,然后是它的所有参数,这些参数是消息相关的。序号类型 (、、、、...) 按原样传输(不进行大端/小端转换)。字符串以 Unicode 字符集 (UTF16) 传输,前面的字符以字符为单位指定字符串的长度。ULONGUCHARUSHORTdoubleULONG

首先,我们需要以下消息类型:

  1. 登录。包含客户端版本 ()、用户名(字符串)、密码(字符串)。ULONG
  2. 登录结果。包含登录结果代码 ()。0=正常,1=凭据无效,依此类推。UCHAR
  3. 聊天消息。包含收件人用户名(字符串)、聊天文本(字符串)、一些额外的代码 ()。ULONG

那么,我们如何实现这一点呢?对于每种消息类型,我们需要以下内容:

  • 消息类/结构的声明。
  • 将此消息写入流(套接字/文件/等)的代码。
  • 分析流中的消息的代码。
  • 处理传入消息的代码。

出于此示例的目的,我们将使用以下抽象类进行流式处理:

C++

收缩 ▲   

struct OutStream {

    virtual void Write(LPCVOID pPtr, size_t nSize) = 0;

    // ordinal types    template <class T>

    void Write_T(const T& val)

    {

        Write(&val, sizeof(val));

    }

    // variable-sized strings    void Write_Str(const CString& val)

    {

        ULONG nLen = val.GetLength();

        Write_T(nLen);

        Write((PCWSTR) val, nLen * sizeof(WCHAR));

    }

};struct InStream {

    virtual size_t Read(LPVOID pPtr, size_t nSize) = 0;

    bool ReadExactTry(LPVOID pPtr, size_t nSize)

    {

        while (true)

        {

            size_t nPortion = Read(pPtr, nSize);

            if (nPortion == nSize)

                return true; // ok            if (!nPortion)

                return false; // not enough data.            nSize -= nPortion;

            if (pPtr)

                ((PBYTE&) pPtr) += nPortion;

        }

    }

    void ReadExact(LPVOID pPtr, size_t nSize)

    {

        if (!ReadExactTry(pPtr, nSize))

        {

            // not enough data, raise an appropriate exception            throw _T("not enough data!");

        }

    }

    // ordinal types    template <class T>

    void ReadExact_T(T& val)

    {

        ReadExact(&val, sizeof(val));

    }

    // variable-sized strings    void ReadExact_Str(CString& val)

    {

        ULONG nLen;

        ReadExact_T(nLen);

        PWSTR szPtr = val.GetBuffer(nLen);

        ReadExact(szPtr, nLen * sizeof(WCHAR));

        val.ReleaseBuffer(nLen);

    }

};

现在,让我们实现我们的消息。例如,可以按以下方式声明登录消息:

C++

收缩 ▲   

struct MsgLogin

{

    // message fields    ULONG m_Version;

    CString m_Username;

    CString m_Password;

    MsgLogin()

    {

        // zero-init members.        m_Version = 0;

    }

    void

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C/C++宏编程 的相关文章

  • 在 C/C++ 中获得正模数的最快方法

    通常在我的内部循环中 我需要以 环绕 方式索引数组 因此 例如 如果数组大小为 100 并且我的代码要求元素 2 则应该给它元素 98 高级语言 例如 Python 可以简单地使用my array index array size 但由于某
  • QCombobox 向下箭头图像

    如何更改Qcombobox向下箭头图像 现在我正在使用这个 QSS 代码 但这不起作用 我无法删除向下箭头边框 QComboBox border 0px QComboBox down arrow border 0px background
  • 为什么在创建矩阵类时使用向量不好?

    对于我的矩阵类 我做了 template
  • 根据 N 个值中最小的一个返回不同的结果

    不确定如何使标题更具描述性 所以我只是从一个例子开始 我使用下面的代码位 它从枚举中选择一个方向 具体取决于四个轴中哪一个与给定方向相比形成最小角度 static Direction VectorToDirection Vector2 di
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行
  • vs2008 c#:Facebook.rest.api如何使用它来获取好友列表?

    如何在此基础上取得进一步的进步 获取好友列表的下一步是什么 string APIKey ConfigurationManager AppSettings API Key string APISecret ConfigurationManag
  • 从 WebBrowser 控件 C# 获取滚动值

    我试图在 WebBrowser 控件中获取网页的 Y 滚动索引 但无法访问内置滚动条的值 有任何想法吗 对于标准模式下的 IE 使用文档类型 正如你所说 scrollTop是的财产元素 而不是 HtmlDocument htmlDoc th
  • AES 输出是否小于输入?

    我想加密一个字符串并将其嵌入到 URL 中 因此我想确保加密的输出不大于输入 AES 是可行的方法吗 不可能创建任何始终会创建比输入更小的输出的算法 但可以将任何输出反转回输入 如果您允许 不大于输入 那么基本上您只是在谈论同构算法alwa
  • 如何在标准 WPF ListView 中启用 UI 虚拟化

    我正在使用 NET 4 5 VS2012 并且我有一个 ListView 看起来像这样
  • 无法在内存位置找到异常源:cudaError_enum

    我正在尝试确定 Microsoft C 异常的来源 test fft exe 中 0x770ab9bc 处的第一次机会异常 Microsoft C 异常 内存位置 0x016cf234 处的 cudaError enum 我的构建环境是 I
  • 每个租户的唯一用户名和电子邮件

    我正在使用以下代码编写多租户应用程序ASP NET Core 2 1 我想覆盖默认的与用户创建相关的验证机制 目前我无法创建多个具有相同的用户UserName My ApplicationUser模型有一个名为TenantID 我想要实现的
  • 如何在c的case语句中使用省略号?

    CASE expr no commas ELLIPSIS expr no commas 我在c的语法规则中看到了这样的规则 但是当我尝试重现它时 int test float i switch i case 1 3 printf hi 它失
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • 新任务中使用的依赖注入服务

    我在需要时使用依赖项注入来访问我的服务 但我现在想要创建一个并发任务 但这会由于依赖项注入对象及其生命周期而导致问题 我读过这篇文章 标题 防止多线程 Link http mehdi me ambient dbcontext in ef6
  • 了解使用 Windows 本机 WPF 客户端进行 ADFS 登录

    我已经阅读了大量有关 ADFS 与 NodeJS Angular 或其他前端 Web 框架集成以及一般流程如何工作的文献 并通过 Auth0 Angular 起始代码构建了概念证明 但我不明白如何这可以与本机 WPF Windows 应用程
  • Pip 无法在 Windows 上安装 Twisted

    我正在尝试在 Windows 8 计算机上安装 Twisted 在 Twisted 官方网站上 只有一个 Windows 版的 Wheel 文件 https twistedmatrix com trac wiki Downloads htt
  • 矩阵到数组 C#

    这将是转换方阵的最有效方法 例如 1 2 3 4 5 6 7 8 9 into 1 2 3 4 5 6 7 8 9 in c 我在做 int array2D new int 1 2 3 4 5 6 7 8 9 int array1D new
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造
  • QFileDialog::getSaveFileName 和默认的 selectedFilter

    我有 getSaveFileName 和一些过滤器 我希望当用户打开 保存 对话框时选择其中之一 Qt 文档说明如下 可以通过将 selectedFilter 设置为所需的值来选择默认过滤器 我尝试以下变体 QString selFilte

随机推荐

  • 全通系统定义、零极点关系、应用

    全通系统定义 表示方法 应用一 将任意因果稳定系统转化为 全通系统和最小相位系统 的级联 应用二 级联一个全通系统可以使非稳定滤波器变成一个稳定滤波器 把非稳定系统的单位圆外的极点映射到单位圆内 应用三 作为相位均衡器 校正系统的非线性相位
  • Android一键清理原理

    欢迎转载 转载请注明 http blog csdn net zhgxhuaa 说明 在总篇中提到过垃圾清理 本篇将着重介绍针对缓存 卸载残留 无用数据等 静态内容 的清理 有关于系统进程的清理以及手机加速的相关功能 将放到 手机加速篇 中介
  • 在腾讯云服务器上安装docker

    一 准备事项 1 1 查看系统版本 uname a docker官方说至少3 8以上 建议3 10以上 root VM 0 11 centos docker uname a Linux VM 0 11 centos 3 10 0 1062
  • 前端面经高频考点

    文章目录 HTML 1 高频1之行内元素 块级元素 行内块元素的区别 2 高频2之script标签中defer和async的区别 3 src和href的区别 4 lable的作用 5 ifram的使用以及有优缺点 6 img的srcset属
  • Java题目练习

    编程题目 题目1 编写MobilePhone类 包含brand 品牌 和price 价格 属性 该类实现Comparable接口规定该类对象大小 即手机能按照价格来排序 2 创建一个只可放 MobilePhone 类的链表 链表当中添加3个
  • geckodriver的安装和测试其是否安装成功

    1 首先下载最新的geckodriver 你可以百度 或者我分享给你 但是如果你看到这篇文的时候 已经更新版本了 你可以去百度一下 总有人在分享的 链接 https pan baidu com s 1L9GLCpLNmgL2szxD6wvK
  • 《科学伦理与学术规范》 课后习题_答案 2022春季

    资料来源网络 侵删 科学伦理与学术规范答案汇总 2022 第一部分 必做 ABC A B D ABCD ABC D A BCD C D D 第二部分 必做 ABCD ABCD ABCD BCD AD A ABCD ACD AC A AC D
  • 了解接口工具Apifox

    最近发现一款接口测试工具 apifox 我我们很难将它描述为一款接口管理工具 或 接口自测试工具 官方给了一个简单的公式 更能说明apifox可以做什么 Apifox Postman Swagger Mock JMeter Apifox的特
  • /usr/bin/ld: cannot find -lmysqlcllient

    文章目录 1 question usr bin ld cannot find lmysqlcllient 2 solution 1 question usr bin ld cannot find lmysqlcllient 2 soluti
  • Unity脚本的属性

    参考官网 http game ceeger com Script Attributes Attributes html http blogs unity3d com 2014 06 24 serialization in unity 参考文
  • 解决UE4启动出现UE4Editor.exe-无法找到dll入口的弹窗

    UE4编辑器启动 一开始遇到的问题如下 上网找问题得到的解答都是在cmd下利用regsvr32 exe注册该dll到注册表 但是也提示报错 上网搜了一下 得知原因是生成该dll的源码没有实现 DllRegisterServer和DllUne
  • 镜像iso文件下载地址

    CentOS 7官方下载地址 https www centos org download Centos国内下载源 以下链接均可下载镜像文件 http man linuxde net download CentOS http centos u
  • 面向对象程序设计语言(Java)-1.概述

    概述 1 Java的两层含义 2 Java语言的特点 3 Java的应用平台 4 Java的工作原理 5 Java环境中的概念 6 初始Java程序 7 Java程序的基本组成 8 开发Java程序的步骤 9 注释 1 Java的两层含义
  • JavaScript中的扁平化数据转换为树形结构、树形结构扁平化数据

    1 扁平化数据 gt 树形结构 1 1 第一种数据类型 原始数据只有id和pId相互关联 let data id 639 name 商品管理 type 0 pId 638 code 1 domain id 640 name 商品分类 typ
  • antdv(vue)组件中tree-select使用

    官网教程 组件tree select 实现效果 1 基本用法 直接使用 在vue层写数据 注意 注册组件要包含treeSelect和其中的节点ATreeSelectNode 不注册会报错 如下
  • Oracle常用代码总结

    1 用户 创建用户 create user dm identified by dm default tablespace BIGDATA DM temporary tablespace DM TEMP profile default 修改用
  • Centos7 搭建 Minikube

    Centos7 搭建 Minikube 目录 Centos7 搭建 Minikube 参考博客 运行环境 安装过程 配置系统环境 安装Docker 安装Kubectl 参考博客 参考博客 运行环境 系统版本 CentOS Linux rel
  • Flutter 页面中添加水印、自定义水印

    最近开发手机APP 使用 Fltter 由于需要使用水印的功能 但是第一次接触Flutter 就想着能不能在网上找到现成的使用 结果全是一群复制粘贴的 还卵用没有 不过由于我太机制 直接去官方的 pub get 找到一个插件 嘿嘿 pub
  • 教你统计日留存、周留存、月留存率更准确的方法。

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 什么是留存用户 某段时间内的新增用户 经过一段时间后 仍继续使用应用的被认作是留存用户 这部分用户占当时新增用户的比例即是留存率 统计留存用户的时间粒度有哪些 自然日 包括
  • C/C++宏编程

    C C 宏编程 宏的复杂使用 永远不要写两次 介绍 我读过的所有C C 教科书都批评宏的使用 不要使用它们 它们很危险 因为它们隐藏了你实际写的东西 尤其是看起来很实用的宏 有些人甚至说 没有理由在C 的模板类的发明中使用宏 尽管如此 宏仍