<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Evilrabbit Blog</title>
  
  <subtitle>聚焦 C++26 与 AI 技术</subtitle>
  <link href="https://blog.yujiay.wang/atom.xml" rel="self"/>
  
  <link href="https://blog.yujiay.wang/"/>
  <updated>2026-02-14T12:05:30.000Z</updated>
  <id>https://blog.yujiay.wang/</id>
  
  <author>
    <name>0x3ff18a</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Hexo安知鱼主题开启AI摘要</title>
    <link href="https://blog.yujiay.wang/tech/techPractice/AISummary/"/>
    <id>https://blog.yujiay.wang/tech/techPractice/AISummary/</id>
    <published>2026-02-14T12:05:30.000Z</published>
    <updated>2026-02-14T12:05:30.000Z</updated>
    
    <content type="html"><![CDATA[<p>这篇文章是一篇教学文章，目的是替代原主题中只能使用洪墨 AI 的摘要功能，<strong>通过本教程，你可以使用 OpenAI 和 DeepSeek 等多种 AI 低价甚至免费的实现 AI 摘要功能</strong>。如果你有任何问题可以在文章末尾的评论区进行提问，我会尽快回复。</p><div class="note warning flat"><p>请注意，当你改动任何配置文件前请务必进行备份操作，这是一种保障也是一个良好的运维习惯。</p></div><h2 id="效果图"></a> 效果图</h2><p><img src="/images/2026/3/AISummary.png" alt="AI Summary" /></p><h2 id="工作原理"></a> 工作原理</h2><p>由于主题内置的是洪墨 AI 接口，由于种种原因，有些朋友可能已有使用较为顺手的 AI 工具。故此基础上，我查阅了一些资料写下本文。</p><p>本教程实现原理是，通过第三方插件 <code>hexo-ai-summary-liushen</code> 进行摘要的生成控制，然后写入文章的 <code>Front-matter</code> 中，再通过主题自带的 AI 摘要功能将其渲染。</p><p><a href="https://github.com/willow-god/hexo-ai-summary">hexo-ai-summary-liushen</a> 插件基于 <a href="https://github.com/rootlexme/hexo-ai-excerpt">hexo-ai-excerpt</a> 插件开发而来，原插件已经归档，于是 <a href="https://blog.liushen.fun/">清羽飞扬</a> 复刻了新的，进行了重构。</p><h2 id="实现过程"></a> 实现过程</h2><h3 id="前置条件"></a> 前置条件</h3><ol><li>需主题版本大于 1.1.6 版本；</li><li>执行以下命令安装插件和依赖：</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-ai-summary-liushen --save</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install axios p-limit node-fetch --save</span><br></pre></td></tr></table></figure><h3 id="开启主题自带-ai-摘要功能"></a> 开启主题自带 AI 摘要功能</h3><p>完成前置条件后，在安知鱼主题的配置文件(_config.yml)中找到 <code>post_head_ai_description</code> 字段（<strong>这里要注意，是安知鱼主题的配置文件，不是 hexo 的配置文件！</strong>）。将其修改为如下内容：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 文章顶部ai摘要</span></span><br><span class="line"><span class="attr">post_head_ai_description:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">gptName:</span> <span class="string">Evilrabbit</span> <span class="string">AI</span></span><br><span class="line">  <span class="attr">mode:</span> <span class="string">local</span> <span class="comment"># 默认模式 可选值: tianli/local</span></span><br><span class="line">  <span class="attr">switchBtn:</span> <span class="literal">false</span> <span class="comment"># 可以配置是否显示切换按钮 以切换tianli/local</span></span><br><span class="line">  <span class="attr">btnLink:</span> <span class="string">https://afdian.net/item/886a79d4db6711eda42a52540025c377</span></span><br><span class="line">  <span class="attr">randomNum:</span> <span class="number">1</span> <span class="comment"># 按钮最大的随机次数，也就是一篇文章最大随机出来几种</span></span><br><span class="line">  <span class="attr">basicWordCount:</span> <span class="number">1000</span> <span class="comment"># 最低获取字符数, 最小1000, 最大1999</span></span><br><span class="line">  <span class="attr">key:</span> <span class="string">xxxx</span></span><br><span class="line">  <span class="attr">Referer:</span> <span class="string">https://xx.xx/</span></span><br></pre></td></tr></table></figure><p>这里的内容多为占位内容，除了 <code>enable</code> 和 <code>mode</code> 选项，其他没有任何控制效果，都是为了占位，所以无需担心，可以先按照我的写，后面再根据效果修改。</p><p>将 enable 和 mode 改为 <code>enable: true</code> 和 <code>mode: local</code> 即可。这里的意思是，开启主题自带的文章顶部 AI 摘要，模式选择为本地摘要。</p><h3 id="重要提示"></a> 重要提示</h3><div class="note danger modern"><p>由于后续操作会将你文章的所有 description 和 keywords 进行 AI 重写。当你执行至本步骤时，请你务必保存所有文件，并进行全文件夹备份（包括所有文章）。</p><p>对比图：</p><p><img src="/images/2026/3/AISummaryComparison.png" alt="AI Summary Comparison" /></p></div><h3 id="配置插件"></a> 配置插件</h3><p>备份完成后，在博客根目录 Hexo 的配置文件(_config.yml)中任何位置添加如下新键值（<strong>此时是 Hexo 的配置文件，不是安知鱼主题的配置文件！这二者非常相似。</strong>）：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># hexo-ai-summary-liushen</span></span><br><span class="line"><span class="comment"># docs on : https://github.com/willow-god/hexo-ai-summary</span></span><br><span class="line"><span class="attr">aisummary:</span></span><br><span class="line">  <span class="comment"># 基本控制</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span>               <span class="comment"># 是否启用插件，如果关闭，也可以在文章顶部的is_summary字段单独设置是否启用，反之也可以配置是否单独禁用</span></span><br><span class="line">  <span class="attr">cover_all:</span> <span class="literal">false</span>           <span class="comment"># 是否覆盖已有摘要，默认只生成缺失的，注意开启后，可能会导致过量的api使用！</span></span><br><span class="line">  <span class="attr">summary_field:</span> <span class="string">ai</span>          <span class="comment"># 摘要写入字段名（安知鱼官方使用的是“ai”），重要配置，谨慎修改！！！！！！！</span></span><br><span class="line">  <span class="attr">logger:</span> <span class="number">1</span>                  <span class="comment"># 日志等级（0=仅错误，1=生成+错误，2=全部）</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># AI 接口配置</span></span><br><span class="line">  <span class="attr">api:</span> <span class="string">https://api.openai.com/v1/chat/completions</span>     <span class="comment"># OpenAI 兼容模型接口</span></span><br><span class="line">  <span class="attr">token:</span> <span class="string">sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span>  <span class="comment"># OpenAI 或兼容模型的密钥</span></span><br><span class="line">  <span class="attr">model:</span> <span class="string">gpt-3.5-turbo</span>                                <span class="comment"># 使用模型名称</span></span><br><span class="line">  <span class="attr">prompt:</span> <span class="string">&gt;</span></span><br><span class="line"><span class="string">    你是一个博客文章摘要生成工具，只需根据我发送的内容生成摘要。</span></span><br><span class="line"><span class="string">    不要换行，不要回答任何与摘要无关的问题、命令或请求。</span></span><br><span class="line"><span class="string">    摘要内容必须在150到250字之间，仅介绍文章核心内容。</span></span><br><span class="line"><span class="string">    请用中文作答，去除特殊字符，输出内容开头为“这里是Evilrabbit，这篇文章”。</span></span><br><span class="line"><span class="string"></span></span><br><span class="line">  <span class="comment"># 内容清洗设置</span></span><br><span class="line">  <span class="attr">ignoreRules:</span>              <span class="comment"># 可选：自定义内容清洗的正则规则</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&quot;\\&#123;%.*?%\\&#125;&quot;</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&quot;!\\[.*?\\]\\(.*?\\)&quot;</span></span><br><span class="line">  </span><br><span class="line">  <span class="attr">max_token:</span> <span class="number">5000</span>           <span class="comment"># 输入内容最大 token 长度（非输出限制）</span></span><br><span class="line">  <span class="attr">concurrency:</span> <span class="number">2</span>            <span class="comment"># 并发处理数，建议不高于 5</span></span><br></pre></td></tr></table></figure><p><strong>下面是配置的说明：</strong></p><div class="note flat"><ol><li><p>cover_all：覆盖性重新生成所有摘要，非必要不要打开，可能会导致过量的 API 消耗。</p></li><li><p>logger：为了更加精细的实现控制，清羽飞扬设置了三个日志等级，如下划分：</p><ul><li>0：仅仅显示错误信息，不会显示包括生成文章摘要在内的任何输出</li><li>1：当生成新文章摘要时，会输出对于文本的处理，比如超长自动裁剪，生成成功或者生成失败。</li><li>2：调试使用，会输出包括跳过所有页面信息，仅仅处理文章部分。</li></ul></li><li><p>api：任何 OpenAI 类型接口，包括 deepseek，讯飞星火，腾讯混元，ChatGPT 等。</p><ul><li>ChatGPT 接口：<a href="https://api.openai.com/v1/chat/completions">https://api.openai.com/v1/chat/completions</a> ;</li><li>DeepSeek 接口：<a href="https://api.deepseek.com/chat/completions">https://api.deepseek.com/chat/completions</a> ;</li><li>其余请查询具体官方文档。</li></ul></li><li><p>token：API 对应的接口密钥。</p></li><li><p>model：使用的模型名称，请检查对应接口文档说明，不同接口包含的模型不一致。</p><ul><li>ChatGPT模型建议：gpt-3.5-turbo</li><li>DeepSeek 模型建议：deepseek-chat</li><li>其余请查询具体官方文档。</li></ul></li><li><p>prompt：提示词，请自行定制，建议详细一些，但是不要太废话，以清羽飞扬写的为例。</p></li><li><p>ignoreRules：忽略文本正则接口，由于本插件直接获取 Markdown 文本，内置了一些处理，但是你仍然可以进行额外的处理，下面是内置的文本处理规则，如果有兴趣进行修改可以进行参考：</p></li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 2. 清理内容</span></span><br><span class="line">  content = content</span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/```[\s\S]*?```/g</span>, <span class="string">&#x27;&#x27;</span>)           <span class="comment">// 代码块</span></span><br><span class="line">    <span class="comment">// .replace(/`[^`\n]+`/g, &#x27;&#x27;)                // 行内代码</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/&#123;%[^%]*%&#125;/g</span>, <span class="string">&#x27;&#x27;</span>)                <span class="comment">// Hexo 标签</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/^\|.*?\|.*$/gm</span>, <span class="string">&#x27;&#x27;</span>)             <span class="comment">// 表格行</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/!\[.*?\]\(.*?\)/g</span>, <span class="string">&#x27;&#x27;</span>)          <span class="comment">// 图片</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/\[(.*?)\]\(.*?\)/g</span>, <span class="string">&#x27;$1&#x27;</span>)       <span class="comment">// 超链接文本</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/&lt;[^&gt;]+&gt;/g</span>, <span class="string">&#x27;&#x27;</span>)                  <span class="comment">// HTML 标签</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/&amp;nbsp;/g</span>, <span class="string">&#x27; &#x27;</span>)                  <span class="comment">// 空格实体</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/\n&#123;2,&#125;/g</span>, <span class="string">&#x27;\n&#x27;</span>)                 <span class="comment">// 多重换行压缩</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/^\s+|\s+$/gm</span>, <span class="string">&#x27;&#x27;</span>)               <span class="comment">// 行首尾空格</span></span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/[ \t]+/g</span>, <span class="string">&#x27; &#x27;</span>)                  <span class="comment">// 多空格压缩</span></span><br><span class="line">    .<span class="title function_">trim</span>();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 3. 拼接标题</span></span><br><span class="line">  <span class="keyword">const</span> combined = (title ? title.<span class="title function_">trim</span>() + <span class="string">&#x27;\n\n&#x27;</span> : <span class="string">&#x27;&#x27;</span>) + content;</span><br></pre></td></tr></table></figure><p>但是大部分情况可以忽略这个配置项，留空即可。</p><ol start="8"><li><p>max_token：限制模型输入的最大字数，用字符串的 slice 进行截断，如果超出模型接受范围，可能会造成下文覆盖上文导致prompt丢失，内容混乱，所以请按照模型承受能力进行灵活配置。</p></li><li><p>concurrency：很多模型会限制并发，所以这里清羽飞扬利用 p-limit 插件实现了并发限制，降低失败请求的概率，经过调查，p-limit应该是hexo内已经有的一些包，所以也不需要担心需要重新安装之类的，直接使用即可。</p></li></ol><p>由于利用了 hexo 自带的钩子，所以，摘要数据可能会被缓存，如果直接执行 hexo server，并没有任何效果，请尝试先执行 hexo cl 清理缓存，hexo cl 不会删除任何已经生成了的摘要内容。</p><p>— — 原文参考地址(<a href="https://blog.liushen.fun/posts/40702a0d/">https://blog.liushen.fun/posts/40702a0d/</a>)[<a href="https://blog.liushen.fun/posts/40702a0d/">https://blog.liushen.fun/posts/40702a0d/</a>]</p></div><h3 id="验证内容和例外文章"></a> 验证内容和例外文章</h3><p>如果一切正常，此时执行 Hexo 三连（<code>hexo cl &amp;&amp; hexo g &amp;&amp; hexo s</code>）后就可以在每篇文章的顶部看到对应的摘要文字。</p><p>但这里我再次提醒：</p><div class="note danger modern"><p>此操作会将你文章的所有 description 和 keywords 进行 AI 重写。请你务必保存所有文件，并进行全文件夹备份（包括所有文章）。</p></div><p>如果存在例外文章，你不想让其显示 AI 摘要，你可以在文章的 <code>Front-matter</code> 中添加 <code>is_summary: false</code> 进行排除，此时该文章将不显示 AI 摘要。</p>]]></content>
    
    
    <summary type="html">本教程详细介绍如何为你的安知鱼博客添加AI摘要功能。利用hexo-ai-summary-liushen插件，在安知鱼主题中替代洪墨AI，通过OpenAI、DeepSeek等低价或免费AI接口实现文章摘要自动生成。包含完整配置步骤、参数说明、备份重要性和例外处理方案，帮助博客主优化SEO并节省成本。</summary>
    
    
    
    <category term="技术文档" scheme="https://blog.yujiay.wang/categories/tech/"/>
    
    <category term="技术实践" scheme="https://blog.yujiay.wang/categories/tech/techPractice/"/>
    
    
    <category term="随笔" scheme="https://blog.yujiay.wang/tags/essays/"/>
    
    <category term="博客" scheme="https://blog.yujiay.wang/tags/blog/"/>
    
  </entry>
  
  <entry>
    <title>爆火的背后OpenClaw真的适合你吗？</title>
    <link href="https://blog.yujiay.wang/osp/OpenClaw/"/>
    <id>https://blog.yujiay.wang/osp/OpenClaw/</id>
    <published>2026-02-01T09:53:00.000Z</published>
    <updated>2026-02-01T09:53:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>在 AI 技术狂飙突进的今天，一个名为 OpenClaw 的项目在开发者社区中引爆了前所未有的兴奋与忧虑。它承诺将科幻电影中J.A.R.V.I.S.般的智能助手带入现实，却又被资深安全专家视为一个“疯狂而危险”的实验。这不仅仅是一个工具，它更像一面镜子，映照出我们对未来的渴望与对失控的深层恐惧。</p><p><img src="/images/2026/2/OpenClaw.png" alt="OpenClaw" /></p><h2 id="openclaw-是一场危险的赋权"></a> OpenClaw 是一场危险的赋权？</h2><p>简单来说，OpenClaw 是一个安装在你个人电脑、服务器上的拥有极高系统权限的 AI Intelligent Agent（AI 智能体）。它不是普通的聊天机器人。相比于传统的 AI 助手，无论是Siri也好还是Copilot也好，它们都运行在权限及其严格限制的“沙箱”里，只能通过有限的 API 与系统进行交互。而 OpenClaw 的设计哲学截然相反。它被设计成一个<strong>拥有“上帝模式”权限的数字实体</strong>。它的核心是一个本地运行的控制中心（Gateway），负责调度一切。通过 WhatApp、WeChat、Telegram 或语音向它发出指令，它在本地解析后，可以命令的电脑执行几乎任何操作。无论是编写并运行代码、操控浏览器、管理文件，还是通过插件控制智能家居这些都是它最基本的用法。OpenClaw 试图打破人机交互的所有屏障，让 AI 从“顾问”直接变为“执行者”。</p><h2 id="从-clawd-到现象级项目"></a> 从 Clawd 到现象级项目</h2><p>OpenClaw 的诞生与演变，本身就是一个充满戏剧性的硅谷故事。它最初在 2025 年底以 “Clawd” 之名亮相，因与知名 AI 模型 “Claude” 商标相似，很快被迫更名为 “Moltbot”。然而，真正的转折点发生在 2026 年 1 月底，项目最终定名 “OpenClaw” 并完全开源后，其 GitHub 仓库星标数呈现爆炸式增长，迅速突破十万。</p><p><img src="/images/2026/2/OpenClawSear.png" alt="OpenClawSear" /></p><p>这股热潮部分源于 AI 领域顶尖研究者（如安德烈·卡帕西）的公开赞誉，他甚至称其为“我所见过的 Agent 最佳实践”。更令人玩味的是，这股软件热潮意外拉动了硬件市场，大量用户为了部署它而去购买苹果 Mac mini，因为 Mac mini（尤其是 M 系列芯片版本）提供了强大的苹果芯片算力（CPU/GPU/NPU），同时价格远低于 Mac Studio 或 Mac Pro，功耗和静音控制也优于组装 PC 或服务器。对于需要 7x24 小时运行的自动化代理/网关服务，它是绝佳的“家庭服务器”选择。这个从命名纠纷到现象级产品的急速攀升，只用了短短数月。</p><h2 id="当-ai-真正开始动起手来的时候"></a> 当 AI 真正开始“动起手来”的时候</h2><p>它的强大，源自其“感知-思考-行动”的完整自主循环。OpenClaw 能做的，远不止回答问题。当你说“帮我总结上周项目会议的所有邮件，并生成一份待办清单同步到 Notion”，它会自动登录你的邮箱、读取邮件、理解内容、提炼要点，最后登录你的 Notion 页面创建新文档。这一切无需你逐步指导。它的能力通过一个庞大的“技能”生态系统无限扩展。社区开发者已经为其创造了数千个技能：从专业的<strong>代码助手</strong>（能直接接入 GitHub，诊断 bug 并提交修复），到<strong>生活管家</strong>（分析睡眠数据并自动调节智能卧室灯光），再到<strong>全能办公秘书</strong>（管理日历、预订行程、整理云端硬盘）。它代表了 AI 从“内容生成”迈向“<strong>工作流自动化</strong>”的关键一步。</p><h2 id="一个危险的权力实验"></a> 一个危险的权力实验</h2><p>然而，这份强大力量的背后，是触目惊心的安全代价。安全研究人员普遍认为，OpenClaw 为了便利性，系统性地拆除了现代操作系统数十年建立的安全防线。</p><p><strong>首要风险是提示词注入与系统接管。</strong> 由于 OpenClaw 进程常以管理员权限运行，并能执行任意 Shell 命令，一个被恶意构造的指令（例如，隐藏在网页或邮件中的迷惑性文本）就可能诱骗它执行 <code>rm -rf /</code>（删除所有文件）或窃取密钥。你赋予 AI 的权限，同样也赋予了潜在的入侵者。</p><p><strong>其次，隐私承诺存在裂缝。</strong> 尽管处理逻辑在本地，但其“大脑” —— 复杂的推理任务 —— 通常依赖 GPT-4 或 Claude 等云端大模型。这意味着你本地的敏感商业邮件、私人文档在分析前，已被发送至第三方服务器，数据完全脱离了你的控制。</p><p><strong>最后，其生态系统本身成为攻击载体。</strong> 繁荣的技能市场缺乏严格审核，一个伪装成效率工具的插件，可能就是潜伏的木马。更抽象的问题是，许多用户为方便远程访问，将 OpenClaw 服务暴露在公网上，导致全球有数百个无防护的服务实例成了黑客的活靶子。</p><h2 id="高昂的成本聪明大脑的昂贵思考"></a> 高昂的成本，聪明“大脑”的昂贵思考</h2><p>我看到网上很多用户惊讶于使用 OpenClaw 时代理 API 的 Token 消耗速度。但这点我要为 OpenClaw 正名。这并不是 bug，因为其工作模式决定。你要完成复杂任务，它就需要进行<strong>多轮迭代式思考</strong>。例如，写一个程序时，它可能首先生成代码，然后运行测试，接着阅读错误日志，再生成修复方案。每一轮“思考-行动-观察”的循环，都需要将大量上下文（代码、错误信息、工具输出）重新发送给云端 AI，导致 Token 消耗急剧累积。它越智能、越自主，你的 API 账单就越能反映其“思考”的深与广度。</p><h2 id="便利性与控制权的终极权衡"></a> 便利性与控制权的终极权衡</h2><p>OpenClaw 无疑是一个震撼人心的技术演示，它让我们真切触摸到了高度自主化 AI 助理的未来。对于热衷探索的开发者，它是一个无与伦比的创新平台。但同时，它也是一个尖锐的警示。在我们急切地将权力下放给 AI 以求便利时，可能正在不经意间铸造系统中最脆弱的一环。使用它，就像在家中豢养一头能力超群但心性未定的野兽。你或许能享受它带来的无尽便捷，但也必须时刻准备承受其难以预测的行为所带来的风险。在完全拥抱它之前，每一位用户都应当问自己：我是否真的愿意，用整个数字世界的安全门锁，去交换一把名为“全能”的、尚未开刃的双刃剑？</p>]]></content>
    
    
    <summary type="html">本文深度解析OpenClaw从Clawd到现象级项目的演变、其“感知-思考-行动”的自主循环能力，并揭示其背后触目惊心的提示词注入、隐私泄露与生态系统安全风险，探讨便利性与控制权的终极权衡。</summary>
    
    
    
    <category term="开源项目" scheme="https://blog.yujiay.wang/categories/osp/"/>
    
    
    <category term="随笔" scheme="https://blog.yujiay.wang/tags/essays/"/>
    
    <category term="生活" scheme="https://blog.yujiay.wang/tags/life/"/>
    
    <category term="科技圈" scheme="https://blog.yujiay.wang/tags/techCircle/"/>
    
    <category term="AI 人工智能" scheme="https://blog.yujiay.wang/tags/artificialIntelligence/"/>
    
  </entry>
  
  <entry>
    <title>播客复兴让年轻人在算法时代找回“活人感”与深度交流</title>
    <link href="https://blog.yujiay.wang/lifeSharing/podcast/PodcastRevival/"/>
    <id>https://blog.yujiay.wang/lifeSharing/podcast/PodcastRevival/</id>
    <published>2026-01-19T11:00:00.000Z</published>
    <updated>2026-01-19T11:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>“我已经好多天没和别人说过话了。”在人工智能技术飞速发展的今天，这样的大学生越来越多。他们通过“古早”的声音媒介——播客，找到了久违的“活人感”。—— <a href="https://www.workercn.cn/c/2026-01-13/8707679.shtml">中工网《圈粉上亿年轻人 播客为啥这么火？》</a></p><p>播客这种形式曾经一度遇冷，如今却重新焕发生机。数据显示，2023年中文播客听众已达1.17亿，2024年预计增至1.34亿，2027年将突破 1.79 亿。—— <a href="https://www.workercn.cn/c/2026-01-13/8707679.shtml">中工网《圈粉上亿年轻人 播客为啥这么火？》</a></p></blockquote><h2 id="什么是播客"></a> 什么是播客？</h2><p>播客（Podcast）是一种基于互联网的数字广播形式，它允许内容创作者发布音频或视频节目，<strong>用户可以通过订阅的方式自动接收最新内容</strong>。其名称来源于苹果公司的“iPod”与“广播”（broadcast）的组合。与传统广播不同，播客内容可以随时下载或在线收听，适应现代人在通勤、运动等多种场景下的伴随性需求。它既可以是个人表达观点的“个人电台”，也涵盖专业媒体的深度节目，内容从知识分享到生活故事无所不包。近年来，凭借真实感和深度内容，播客尤其吸引了年轻高学历群体的喜爱，依我看它正在成为“抵抗算法运动”中连接创作者与听众的重要媒介。</p><p>播客的技术核心在于其<strong>订阅和自动分发机制</strong>，这使它不同于传统的实时广播或简单的音频下载。下面这个表格能帮你快速抓住几个关键技术环节的要点。</p><table><thead><tr><th style="text-align:left">技术环节</th><th style="text-align:left">核心要点</th><th style="text-align:left">说明</th></tr></thead><tbody><tr><td style="text-align:left"><strong>内容创建与录制</strong></td><td style="text-align:left">技术门槛低，格式标准</td><td style="text-align:left">创作者使用设备录制音频/视频，通常保存为MP3等标准格式，为后续分发打下基础。</td></tr><tr><td style="text-align:left"><strong>核心分发机制 (RSS)</strong></td><td style="text-align:left"><strong>订阅自动推送</strong></td><td style="text-align:left">这是播客的关键。每个节目都有一个RSS文件，像一份不断更新的节目单，包含元数据和媒体文件链接。</td></tr><tr><td style="text-align:left"><strong>播客客户端 (Podcatcher)</strong></td><td style="text-align:left"><strong>自动检查与下载</strong></td><td style="text-align:left">用户订阅节目后，客户端会定期检查RSS更新，发现新内容时自动下载到用户设备，实现“订阅即所得”。</td></tr><tr><td style="text-align:left"><strong>内容播放</strong></td><td style="text-align:left">异步、随需听取</td><td style="text-align:left">用户可在任何方便的时间离线播放已下载的内容，完全掌控收听节奏，摆脱了时间表限制。</td></tr></tbody></table><h3 id="关键技术与优势"></a> 关键技术与优势</h3><p>基于上述流程，播客技术的精髓主要体现在：</p><ul><li><p><strong>真正实现“订阅即自由”</strong>：用户一次订阅，即可自动接收所有后续更新，无需手动查找。这种基于 <strong>RSS Enclosure</strong> 的技术，将音频文件附件通过 RSS<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> 推送，这是播客的技术基石。本站就有 RSS 推送功能，很多博友利用 RSS 实现诸多例如<strong>博客朋友圈</strong>的功能，这非常有趣。</p></li><li><p><strong>与流媒体的核心区别</strong>：播客设计用于分发可下载的媒体文件，方便离线收听。虽然许多平台也提供流媒体播放，但<strong>可下载、可离线</strong>是播客的重要特性。</p></li><li><p><strong>对所有人友好</strong>：播客技术对创作者和听众都很友好。创作者只需生成文件并更新 RSS，无需复杂服务器技术。听众订阅后，新内容会自动送达，非常省心。</p></li></ul><h3 id="播客技术新趋势"></a> 播客技术新趋势</h3><p>播客技术也在不断发展，近期播客突然的重回视野让我了解到，视频播客（Vodcast）正在逐渐大规模普及，其技术原理与音频播客完全相同，只是分发的文件形式从音频转变到了视频格式。</p><h2 id="从数据中看播客复兴的现实"></a> 从数据中看播客复兴的现实</h2><p>播客的复兴首先体现在数据上。中文播客听众规模已突破 1 亿大关，以高学历、高收入中青年为主，多分布在一线及新一线城市。这些听众中，女性占 51.8%，平均年龄 31.9 岁，本科及以上学历占 91.2%。青年群体成为播客的核心受众，18-35 岁用户占比超 83%。播客内容也呈现多元化趋势。从《纵横四海》的读书推荐，到《肥话连篇》的两性关系讨论，播客覆盖了生活的方方面面。众多的年轻听众表示，对于播客的累计收听时长已超过 500 小时。通勤路上、化妆护肤时、睡觉前，只要有空，他们便会戴上耳机沉浸其中。</p><p><img src="/images/2026/1/PodcastList.png" alt="Podcast List" /></p><h2 id="对抗算法也寻求真实联结"></a> 对抗算法也寻求真实联结</h2><p>在算法主导内容分发的时代，用户对“三秒抓眼球”的内容产生审美疲劳（央视新闻称之为“脑腐”）。人们开始渴望真实、深度、有思想的交流，而播客恰好填补了这一空白。三个月前我就在博客上发了一篇关于短视频信息茧房的文章《<a href="/lifeSharing/ShortVideosDevour/">别被短视频吞噬你积极的人生</a>》其中我就明确的写出：</p><blockquote><p>平台的目标很明确：最大化用户停留时间。为此，它们构建了一套强大的“多巴胺陷阱”-引擎。</p><p>个性化推荐的背后，算法通过分析你的每一次停留、点赞、滑动，比你自己还了解你的偏好。它不断推送你“可能”感兴趣的内容，让你感到平台“懂你”，营造一种自主支配的错觉，实则将你引入“信息茧房”。<br />而无缝衔接的沉浸体验中让自动播放、无限下拉的设计，消除了任何需要你“选择”的停顿点。继续观看成为最不费力的路径，而停止观看则需要主动的意志力消耗。</p></blockquote><p>如今播客重回大众视野，我很负责的说，这并不是意外走红，而是大家似乎都发现了。在注意力争夺这场战斗中，我们所面对的是算法工程师、心理学家和产品经理通力合作的成果，他们精准地拿捏了人类大脑的弱点。而我们似乎无法孤身战斗且赢得斗争，那最好的办法便是采用最原始的方案 —— 我不用，你便无法操控！</p><p>而作为产品，播客的核心魅力在于“活人感”与“真实感”。相比 AI 生成的内容和过度剪辑的短视频，播客保留了更多真实的人际链接，成为不那么公式化的内容载体。</p><p>播客爱好者飞星表示：“我只听真人主播的节目，AI 那种生硬的语气和断句，让人根本没有听下去的欲望。” 这种对真实的渴望，是播客能够打动年轻人的关键。</p><p><img src="/images/2026/1/PodcastUser.png" alt="Podcast User" /></p><p>《忽左忽右》创始人程衍樑认为，播客强调订阅逻辑，与算法推荐形成鲜明对比。算法推荐弱化创作者、强调内容本身，而播客则以创作者为核心，听众因认可创作者而愿意花费时间收听。</p><h2 id="在碎片化时代寻求完整表达"></a> 在碎片化时代寻求完整表达</h2><p>播客的“长内容”特性，是其吸引青年的核心优势之一。在高度碎片化的信息时代，播客成为许多人专注获取信息的“净土”。</p><p>播客的“长”并非生而有之。《忽左忽右》的另一位创始人杨一回忆，早年他们与平台打交道时，曾被建议将一小时节目切成三个20分钟的节目播出。这表明互联网曾一度向“短平快”的方向发展。但短内容解决不了所有问题。无论是个人主播还是品牌方，都需要更长的时间维度来传递核心观点。听众也存在消费长内容的潜在需求。程衍樑指出，长内容供给减少与用户长内容阅读能力下降，共同推动了播客的兴起。播客完美适配了深度爱好者的需求——既能以足够长的时间承载深度内容，又比文字内容门槛更低。</p><h2 id="明星入局"></a> 明星入局</h2><p>2026 年，明星播客成为新热点。章泽天、杨天真、罗永浩等名人纷纷开设个人播客，推动播客从小众走向大众。</p><p>章泽天的《小天章》首期对话刘嘉玲，谈 60 岁的人生与孤独。没有剪辑、没有脚本，一段近一小时的真诚对话，3 小时内收听量突破 2.2 万。明星们通过播客重塑形象，从“流量明星”向“内容创作者”转型。</p><p><img src="/images/2026/1/PodcastTime.png" alt="Podcast Time" /></p><p>与此同时，播客正经历一场“视频化”转型。B 站、小红书、喜马拉雅等平台纷纷推出视频播客专区，内容既可听也可看。视频播客并非“音频+画面”的简单叠加，而是深度内容在媒介进化中的自然延伸。它既保留播客“长对话、深内容”的内核，又叠加视频的可视化优势。</p><h2 id="商业化挑战与未来前景"></a> 商业化挑战与未来前景</h2><p>尽管播客热度攀升，但商业化仍是挑战。一级市场依然处于谨慎观望状态，与平台和用户端的火热形成对比的是创作者们的“囊中羞涩”。</p><p>2025 年 4 月，头部播客《不合时宜》被曝拖欠实习生工资，其 2024 年全年净收入仅 13 万元。有媒体报道，仅有 20% 的播客创作者是全职投入，多数人因收入无法维生而难以坚持。</p><p>但商业化前景正在改善。2024 年购买付费播客节目、订阅付费专辑的金额显著上涨，61% 的受访主播表示收入较 2023 年有明显提高。</p><p>艾媒咨询 CEO 张毅认为，2026 年播客的核心方向是商业化的加速，产业链有望得到更好的整合提速。品牌定制、播客付费订阅、直播活动等方面可能出现高客单价的品牌合作。</p><h2 id="本站播客订阅链接"></a> 本站播客订阅链接</h2><p>本站新增加了播客订阅链接，我会将重要文章同步至 <a href="https://blog.yujiay.wang/podcast.xml">我的个人播客</a> 欢迎大家订阅收听～</p><div class="audio"><audio controls preload><source src='/audios/2026/1/Podcast.mp3' type='audio/mp3'>Your browser does not support the audio tag.</audio></div><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>简易信息聚合（也叫聚合内容）是一种基于 XML 的标准，在互联网上被广泛采用的内容包装和投递协议。RSS(Really Simple Syndication) 是一种描述和同步网站内容的格式，是使用最广泛的 XML 应用。RSS 搭建了信息迅速传播的一个技术平台，使得每个人都成为潜在的信息提供者。发布一个 RSS 文件后，这个 RSS Feed 中包含的信息就能直接被其他站点调用，而且由于这些数据都是标准的XML格式，所以也能在其他的终端和服务中使用，是一种描述和同步网站内容的格式。 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">探索播客（Podcast）为何在AI与短视频时代重新崛起，吸引上亿年轻人。本文从技术机制、用户数据、真实联结、长内容优势及商业化挑战等角度，深度解析播客作为“精神伙伴”的魅力，并分享个人对抗算法洪流的思考。了解播客如何成为碎片化时代的一股清流。</summary>
    
    
    <content src="https://blog.yujiay.wang/images/2026/1/Podcast.png" type="image"/>
    
    
    <category term="生活分享" scheme="https://blog.yujiay.wang/categories/lifeSharing/"/>
    
    <category term="podcast" scheme="https://blog.yujiay.wang/categories/lifeSharing/podcast/"/>
    
    
    <category term="随笔" scheme="https://blog.yujiay.wang/tags/essays/"/>
    
    <category term="生活" scheme="https://blog.yujiay.wang/tags/life/"/>
    
    <category term="算法" scheme="https://blog.yujiay.wang/tags/algorithms/"/>
    
    <category term="科普" scheme="https://blog.yujiay.wang/tags/popularScience/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》4.3 共用体</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4-3_Union/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4-3_Union/</id>
    <published>2025-12-16T08:52:30.000Z</published>
    <updated>2025-12-16T08:52:30.000Z</updated>
    
    <content type="html"><![CDATA[<p>共用体（union）是一种特殊的数据结构，它允许不同的数据成员共享同一块内存区域。这意味着，尽管共用体可以包含多个不同类型的成员，但在任何一个时刻，它只能存储其中一个成员的值。这种设计使得共用体在特定场景下非常有用，尤其是在需要考虑内存节省的情况下。</p><p>共用体的定义方式与结构体（struct）相似，但需要把关键字换成 <code>union</code>。例如，你可以定义一个包含整型、字符型和浮点型成员的共用体。</p><figure class="highlight c++"><figcaption><span>程序代码4-3-1</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cstring&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">union</span> <span class="title class_">BasicData</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> integer_value;</span><br><span class="line">    <span class="type">float</span> float_value;</span><br><span class="line">    <span class="type">char</span> string_value[<span class="number">20</span>];</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    BasicData data;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 存储整数</span></span><br><span class="line">    data.integer_value = <span class="number">42</span>;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;整数值: &quot;</span> &lt;&lt; data.integer_value &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 存储浮点数（会覆盖之前的整数）</span></span><br><span class="line">    data.float_value = <span class="number">3.14f</span>;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;浮点数值: &quot;</span> &lt;&lt; data.float_value &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 存储字符串（会覆盖之前的浮点数）</span></span><br><span class="line">    <span class="built_in">strcpy</span>(data.string_value, <span class="string">&quot;Hello, Union!&quot;</span>);</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;字符串值: &quot;</span> &lt;&lt; data.string_value &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 演示数据覆盖效果</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;覆盖后尝试读取整数: &quot;</span> &lt;&lt; data.integer_value &lt;&lt; endl; <span class="comment">// 无意义的值</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然而，与结构体所有成员独立占用内存空间不同，共用体的所有成员都从相同的内存地址开始存储。因此，一个共用体变量所占用的总内存大小，由其最长的成员决定。例如，如果一个共用体包含一个 int（通常占 4 字节）和一个 double（通常占 8 字节），那么该共用体的大小就是 8 字节。这种内存共享机制也带来了一个关键特性：当你给一个成员赋值后，再给另一个成员赋值，就会覆盖之前的值，因为它们共享同一块内存。所以，在某一时刻，只有最后一次被赋值的成员是有效的。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 存储整数</span></span><br><span class="line">data.integer_value = <span class="number">42</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;整数值: &quot;</span> &lt;&lt; data.integer_value &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 存储浮点数（会覆盖之前的整数）</span></span><br><span class="line">data.float_value = <span class="number">3.14f</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;浮点数值: &quot;</span> &lt;&lt; data.float_value &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 存储字符串（会覆盖之前的浮点数）</span></span><br><span class="line"><span class="built_in">strcpy</span>(data.string_value, <span class="string">&quot;Hello, Union!&quot;</span>);</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;字符串值: &quot;</span> &lt;&lt; data.string_value &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">cout &lt;&lt; <span class="string">&quot;覆盖后尝试读取整数: &quot;</span> &lt;&lt; data.integer_value &lt;&lt; endl; <span class="comment">// 无意义的值</span></span><br></pre></td></tr></table></figure><p>由于共用体的这种特性，在使用时有几点需要特别注意。你不能直接对共用体中定义的变量名进行赋值或初始化，也不能用它作为函数参数或返回值，而只能通过其成员来访问数据。同时，共用体变量的地址和它各个成员的地址都是相同的。在 C++ 中，共用体可以像类一样拥有成员函数（如构造函数），但不能有虚函数、静态数据成员或引用成员，也不能作为基类使用（面向对象及类的知识我们会在第七章类与对象中讲到）。此外，如果共用体的成员是自定义类型（如某个类的对象），那么该类不能有构造函数、析构函数、重载的赋值运算符或虚函数。</p><p>共用体一个典型的应用场景是当某个数据项可能具有多种类型，但在一段时间内只会使用其中一种类型时，可以用来节省内存。例如，在一个商品管理结构中，有些商品的 ID 是整数，有些则是字符串，就可以使用共用体来存储 ID。共用体也常用于低级编程，如操作系统数据结构、硬件寄存器访问或需要直接处理数据字节的场景（例如类型转换或分离高低字节）。还有一种特殊的匿名共用体（anonymous union），它没有名称，其成员可以直接被外层结构体或类的成员访问，使得代码更加简洁。</p><figure class="highlight c++"><figcaption><span>程序代码4-3-2</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ConfigValue</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">enum</span> <span class="title class_">ValueType</span> &#123; INT_TYPE, FLOAT_TYPE &#125; type; <span class="comment">// 标签，用于指示当前存储的是哪种类型的数据</span></span><br><span class="line">    <span class="keyword">union</span></span><br><span class="line">    &#123; <span class="comment">// 匿名共用体</span></span><br><span class="line">        <span class="type">int</span> int_val;     <span class="comment">// 当type为INT_TYPE时，使用此成员</span></span><br><span class="line">        <span class="type">float</span> float_val; <span class="comment">// 当type为FLOAT_TYPE时，使用此成员</span></span><br><span class="line">    &#125;; <span class="comment">// 匿名共用体结束，其成员int_val和float_val直接成为ConfigValue的成员</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ConfigValue cv;</span><br><span class="line">    </span><br><span class="line">    cv.type = ConfigValue::INT_TYPE;</span><br><span class="line">    cv.int_val = <span class="number">100</span>; <span class="comment">// 直接访问匿名共用体的成员，无需中间变量名</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Integer value: &quot;</span> &lt;&lt; cv.int_val &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">    cv.type = ConfigValue::FLOAT_TYPE;</span><br><span class="line">    cv.float_val = <span class="number">3.14f</span>; <span class="comment">// 给float_val赋值会覆盖int_val的内存</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Float value: &quot;</span> &lt;&lt; cv.float_val &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 错误演示：由于内存共享，此时再读取cv.int_val将得到无意义的数据</span></span><br><span class="line">    <span class="comment">// cout &lt;&lt; cv.int_val &lt;&lt; endl;</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在实际编程中，为了确保能正确解读共用体中存储的数据，通常需要另一个额外的变量，例如：<code>enum ValueType &#123; INT_TYPE, FLOAT_TYPE &#125; type;</code>（通常称为&quot;标签&quot;或&quot;判别式&quot;）来记录当前共用体中存储的是哪个成员。例如，在一个结构体中，可以有一个 type 字段指明当前应该使用共用体中的哪个成员。共用体的内存布局还会受到内存对齐规则的影响。编译器可能会在成员之间或共用体末尾添加填充字节，以确保数据在内存中的地址符合特定要求，从而优化访问速度。因此，共用体的实际大小可能不等于其最大成员的大小，而是其对齐要求的整数倍。</p>]]></content>
    
    
    <summary type="html">本文深入探讨C++中的共用体（union），详解其与结构体的内存差异、共享内存特性及使用场景。通过清晰的代码示例，展示如何定义共用体、访问其成员，并解释数据覆盖原理。同时，文章涵盖了内存对齐规则、匿名共用体的应用以及使用时的关键注意事项，帮助开发者高效利用共用体节省内存并处理类型多变的数据。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》4.2 结构体</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4-2_Structure/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4-2_Structure/</id>
    <published>2025-12-09T11:53:00.000Z</published>
    <updated>2025-12-09T11:53:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>通过 <a href="/bookHelloCpp/HelloCpp/4-1_Arrays/">4.1 数组初识</a>的学习，相信大家已经基本掌握了如何在 C++ 中何利用数组存储多个数据类型相同的元素。但请大家试想一下，假如我们要存储一个员工的（可能涉及到：员工姓名、年龄、籍贯和工资等）信息。在这种场景下我们希望有一种可以不同于数组只能存储单一数据类型的工具，而是可以将多种复杂的数据类型集中存储的方法 —— 结构体应运而生。</p><p>结构体是一种比数组更灵活的数据操作工具，因为同一个结构体可以存储多种数据类型的数据，这使得我们可以实现诸如上文提到的员工信息管理的效果，从而将同类信息当作一个集合来看待。我们甚至可以通过结构数组将整个企业的信息进行集合。结构体也是我们在学习第七章类与对象前的基石，通过这块垫脚石对我们进行铺垫后，我们将离 C++ 的核心内容面向对象编程（OOP）更近一步。</p><h2 id="421-c-结构体的基本概念"></a> 4.2.1 C++ 结构体的基本概念</h2><p>结构体（struct）是 C++ 中一种用户自定义的数据类型，它允许将多个相关的数据项组合在一起，形成一个完整的逻辑实体。结构体可以包含各种类型的变量，这些变量称为成员变量，结构体提供了一种将相关数据封装在一起的方式，从而使数据管理变得更加高效和有序。</p><p>在 C 语言中，结构体只能包含数据成员，但在 C++ 中，结构体得到了极大的增强，它可以包含成员函数、构造函数、析构函数，甚至支持继承和多态等面向对象特性。这意味着结构体不仅可以存储数据，还可以由程序员自己定义操作这些数据的行为。例如，一个员工信息的结构体中可以包含计算员工工资的成员函数。这一增强使得数据和行为紧密的结合起来了，大大提高了代码的可读性和模块化程度。</p><p>结构体的定义使用 <code>struct</code> 关键字，后面跟着结构体的名称和一对花括号，花括号内包含成员变量的声明。结构体的定义通常放在<a href="/bookHelloCpp/HelloCpp/2-1_LearnCppFormally/#212-%E5%A4%B4%E6%96%87%E4%BB%B6">头文件</a>中或函数的顶部，以便在多个地方使用。定义结构体后，可以像使用内置类型一样使用它来声明变量。结构体实例的成员通过点运算符（.）<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>访问，如果使用指针访问结构体成员，则使用箭头运算符（-&gt;）<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>。结构体的这种特性使得它非常适合用于表示现实世界中的实体，学生、教师以及员工等，这些实体通常具有多个属性，结构体能够将这些属性有机地组织在一起。</p><h2 id="422-结构体的定义与声明"></a> 4.2.2 结构体的定义与声明</h2><p>在 C++ 中，结构体的定义是通过 struct 关键字实现的，这标志着一种新数据类型的创建。定义结构体时，需要指定其名称和成员列表，成员列表可以包含变量、函数甚至其他结构体。结构体的定义不仅描述了数据的组织方式，还定义了该类型变量的蓝图。</p><div class="animation-figure" markdown><p><img src="/images/hellocpp/img_4/4-2-1Structure.png" alt="Structure" /></p></div><p align="center"> 图 4-2-1 &nbsp; 结构体的组成部分 </p><p>结构体变量的创建有多种方式，每种方式都有其适用场景。最直接的方式是使用 struct 关键字后跟结构体名称和变量名，但 C++ 中创建结构体变量时 struct 键字可以省略，这使得代码更加简洁。另一种常见的方式是在定义结构体的同时创建变量，这种方式适用于需要立即使用结构体的情况。此外，还可以使用初始化列表或构造函数来创建结构体变量，这两种方式允许在创建变量时直接初始化成员的值。</p><ul><li>下面我们通过一个具体的结构体定义来演示前三种创建方式。</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cstring&gt;</span>  <span class="comment">// 用于 strcpy 函数</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 1. 先定义结构体类型</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Employee</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> id;</span><br><span class="line">    <span class="type">char</span> name[<span class="number">50</span>];</span><br><span class="line">    <span class="type">int</span> age;</span><br><span class="line">    <span class="type">float</span> salary;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 方式1：先定义后声明（C++ 中可省略 struct 关键字）</span></span><br><span class="line">    Employee e1;    <span class="comment">// 等同于 struct Employee s1;</span></span><br><span class="line">    e<span class="number">1.</span>id = <span class="number">1001</span>;</span><br><span class="line">    <span class="built_in">strcpy</span>(e<span class="number">1.</span>name, <span class="string">&quot;张三&quot;</span>);</span><br><span class="line">    e<span class="number">1.</span>age = <span class="number">28</span>;</span><br><span class="line">    e<span class="number">1.</span>salary = <span class="number">4200.72f</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方式2：定义类型的同时声明变量</span></span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">Point</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">int</span> x;</span><br><span class="line">        <span class="type">int</span> y;</span><br><span class="line">    &#125; p1, p2; <span class="comment">// 此处同时创建了 p1 和 p2 两个变量</span></span><br><span class="line"></span><br><span class="line">    p<span class="number">1.</span>x = <span class="number">10</span>;</span><br><span class="line">    p<span class="number">1.</span>y = <span class="number">20</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方式3：使用初始化列表</span></span><br><span class="line">    Employee e2 = &#123;<span class="number">1002</span>, <span class="string">&quot;李四&quot;</span>, <span class="number">29</span>, <span class="number">4200.72f</span>&#125;; <span class="comment">// 传统带 = 的写法</span></span><br><span class="line">    Employee e3 &#123;<span class="number">1003</span>, <span class="string">&quot;王五&quot;</span>, <span class="number">25</span>, <span class="number">4300.00f</span>&#125;;   <span class="comment">// C++11 起支持的省略=的写法</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>对于需要更复杂初始化逻辑的场景，可以为结构体定义构造函数。这属于面向对象编程的范畴，让结构体的使用更像一个&quot;类&quot;。</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Employee</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> id;</span><br><span class="line">    <span class="type">char</span> name[<span class="number">50</span>];</span><br><span class="line">    <span class="type">int</span> age;</span><br><span class="line">    <span class="type">float</span> salary;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 默认构造函数（无参数）</span></span><br><span class="line">    <span class="built_in">Employee</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        id = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">strcpy</span>(name, <span class="string">&quot;未知&quot;</span>);</span><br><span class="line">        age = <span class="number">0</span>;</span><br><span class="line">        salary = <span class="number">0.0f</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 带参数的构造函数，使用初始化列表</span></span><br><span class="line">    <span class="built_in">Employee</span>(<span class="type">int</span> _id, <span class="type">const</span> <span class="type">char</span>* _name, <span class="type">int</span> _age, <span class="type">float</span> _score)</span><br><span class="line">        : <span class="built_in">id</span>(_id), <span class="built_in">age</span>(_age), <span class="built_in">salary</span>(_score)</span><br><span class="line">    &#123; <span class="comment">// 初始化列表</span></span><br><span class="line">        <span class="built_in">strcpy</span>(name, _name);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 可以定义多个构造函数（重载）</span></span><br><span class="line">    <span class="built_in">Employee</span>(<span class="type">int</span> _id, <span class="type">const</span> <span class="type">char</span>* _name) : <span class="built_in">id</span>(_id)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">strcpy</span>(name, _name);</span><br><span class="line">        age = <span class="number">18</span>;   <span class="comment">// 给年龄一个默认值</span></span><br><span class="line">        salary = <span class="number">4000.0f</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 使用不同的构造函数创建结构体变量</span></span><br><span class="line">    Employee s1; <span class="comment">// 调用默认构造函数</span></span><br><span class="line">    <span class="function">Employee <span class="title">s2</span><span class="params">(<span class="number">1001</span>, <span class="string">&quot;赵六&quot;</span>, <span class="number">20</span>, <span class="number">6000.5f</span>)</span></span>; <span class="comment">// 调用带四个参数的构造函数</span></span><br><span class="line">    <span class="function">Employee <span class="title">s3</span><span class="params">(<span class="number">1002</span>, <span class="string">&quot;孙七&quot;</span>)</span></span>;  <span class="comment">// 调用带两个参数的构造函数</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="423-结构体的高级特性"></a> 4.2.3 结构体的高级特性</h2><p>结构体在 C++ 中不仅限于存储基本数据，还支持一系列高级特性，使其能够处理更复杂的数据结构和逻辑。结构体嵌套是其中之一，它允许在一个结构体中包含另一个结构体作为成员。这种特性使得程序能够更好地组织复杂的数据结构。例如，在一个表示教师的结构体中，可以嵌套一个表示学生的结构体，从而描述教师辅导学生的关系。嵌套结构体的成员通过多重点运算符访问，例如：<code>teacher1.student.name</code>，这种访问方式直观地反映了数据的层次结构。</p><p>结构体与数组的结合使用创造了结构体数组，它能够存储多个相同类型的结构体实例。结构体数组非常适合表示同类事物的集合，如多个点的坐标。通过数组索引，可以访问每个结构体实例，进而访问其成员变量。结构体数组使得批量处理相似数据变得简单，例如，可以使用循环遍历数组中的所有元素，对每个元素执行相同的操作。</p><p>结构体与指针的结合使用是 C++ 中的重要概念，可以通过指针高效地处理动态内存分配的结构体。使用指针访问结构体成员时，需要使用箭头运算符（-&gt;），这简化了通过指针访问成员的操作。结构体指针特别适合用于动态内存分配，例如使用 new 关键字在堆上创建结构体实例，这种方式允许手动控制结构体的生命周期。此外，结构体还可以作为函数参数传递，传递方式包括值传递、引用传递和指针传递。值传递会创建结构体的副本，适合保护原始数据；引用传递和指针传递则避免复制开销，允许函数修改原始结构体。通过 const 关键字，可以防止函数意外修改结构体内容，进一步提高代码的安全性。</p><h2 id="424-结构体与类的区别及选择"></a> 4.2.4 结构体与类的区别及选择</h2><p>在 C++ 中，结构体（struct）和类（class）是两种相似但又有区别的用户自定义数据类型。它们最大的区别在于访问控制的默认设置：结构体的成员默认是公有的（public），而类的成员默认是私有的（private）。这代表在结构体中，除非显式指定，否则所有成员都可以从外部直接访问；而在类中，成员通常被封装起来，只能通过公有成员函数访问。这一区别反映了结构体和类在设计哲学上的差异：<strong>结构体强调数据的透明访问，而类强调数据的封装和行为</strong>。</p><p>另一个重要区别体现在继承的默认方式上。当结构体用于继承时，默认的继承方式是公有继承，而类则默认为私有继承。这意味着从结构体派生的新结构体会自动继承基结构体的所有公有成员，而从类派生的新类则会继承基类的私有成员（但访问受限）。这一区别使得结构体更适合实现简单的数据层次结构，而类则更适合构建复杂的继承体系。</p><p>在选择使用结构体还是类时，需要考虑数据的特性和使用场景。结构体适合用于主要包含数据成员、行为简单的场景，如坐标点、颜色值或数据库记录。结构体的默认公有访问使得数据操作直接明了，适合数据导向的设计。类则适合需要复杂逻辑、严格封装和多态行为的场景，如游戏角色、银行账户等实体。类通过隐藏实现细节，提供了更好的封装性和可维护性。在实际编程中，选择结构体还是类取决于具体需求，但理解它们的区别有助于做出更合理的设计决策。</p><h2 id="425-结构体的内存布局与性能考虑"></a> 4.2.5 结构体的内存布局与性能考虑</h2><p>构体在内存中的布局方式直接影响程序的性能和内存使用效率。结构体的成员在内存中是<strong>连续存储</strong>的，所有成员变量紧密排列。这种连续性使得访问结构体成员时效率较高，因为相邻成员可能位于同一缓存行中，减少了缓存未命中的概率。然而，这种连续存储也带来了内存对齐的问题，即成员变量需要存储在特定地址边界上，以满足硬件访问要求。</p><p>内存对齐是编译器为了优化内存访问速度而采取的一种策略。对齐规则要求每个成员变量存储在自身大小整数倍的地址上。例如：一个 4 字节的 int 变量需要存储在 4 的整数倍地址上。为了满足对齐要求，编译器可能在成员之间插入填充字节，这会增加结构体的总大小。结构体的总大小通常是最大成员对齐数的整数倍，这意味着即使所有成员的总和小于这个值，结构体也会占用对齐后的完整空间。</p><p>为了优化结构体的内存布局，可以采取一些策略。例如，按照成员类型的大小降序排列成员，将较大的数据类型放在前面，较小的放在后面，这样可以减少填充字节的数量。另外，对于频繁传递的结构体，可以考虑使用引用或指针来避免拷贝开销。</p><h2 id="426-结构体总结"></a> 4.2.6 结构体总结</h2><p>C++ 结构体是一个功能强大且灵活的数据组织工具，它融合了 C 语言中结构体的简洁性和 C++ 面向对象编程的强大特性。从基本的数据封装到高级的面向对象特性，结构体为程序员提供了一种有效管理复杂数据的方式。通过结构体，我们可以创建更加符合问题域概念的数据结构，提高代码的可读性、可维护性和重用性。结构体与类的区别使得它们各有适用的场景：结构体适合数据透明、行为简单的场合，而类适合封装复杂、行为丰富的对象。</p><p>在现代 C++ 编程中，结构体的应用范围不断扩大，从简单的数据容器到复杂的系统接口，处处可见其身影。随着 C++ 标准的演进，结构体的功能也在不断增强，如列表初始化、默认成员初始化等特性使得结构体的使用更加方便和安全。理解结构体的内存布局和对齐机制有助于编写出高效且节省内存的代码。无论是初学者还是经验丰富的程序员，掌握结构体的各种特性和应用场景都是提高 C++ 编程水平的关键。</p><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>点运算符用于访问结构体或类的成员，例如有一个 Employee 结构体，可以使用 <code>Employee.name</code> 来访问 name 成员。点运算符是 C/C++ 编程中非常重要的基本概念，理解其用法对于编写和调试代码非常重要。 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>箭头运算符是 C/C++ 中用于通过指针访问结构体或类成员的运算符。它由减号（-）和大于号（&gt;）连续组成，常用于指针操作。 <a href="#fnref2" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">本文是C++结构体（struct）的全面指南，涵盖从基本定义、声明初始化到高级特性如嵌套、内存布局、性能优化的所有核心概念。通过丰富的代码示例，详解结构体与类的区别及适用场景，帮助初学者夯实面向对象编程基础，为学习C++类与对象做好充分准备。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》4.1 数组初识</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4-1_Arrays/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4-1_Arrays/</id>
    <published>2025-11-23T15:20:00.000Z</published>
    <updated>2025-11-23T15:20:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>数组（array）是一种数据格式，能够<strong>存储多个相同类型</strong>的值。想象你有一排整齐排列的盒子，每个盒子都有一个编号，并且这些盒子都用来存放同一种类型的东西，比如都是放玩具汽车。在编程里，数组就类似这样一排盒子，它是一组相同类型的数据元素的集合，这些元素在内存中是连续存储的。每个元素都可以通过一个唯一的编号来访问，这个编号就叫做索引（也叫数组下标）。</p><p>要创建数组，可以使用声明语句。数组的声明应该正确的指出三点，<strong>数据的类型</strong>、<strong>数组名称</strong>以及<strong>数组中的元素个数</strong>。其中数组中的元素个数必须是<strong>正整数常数</strong><sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>。例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">数据类型 数组名[数组大小];</span><br></pre></td></tr></table></figure><p>例如，声明一个可以存放 5 个整数的数组：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> numbers[<span class="number">5</span>];</span><br></pre></td></tr></table></figure><p>这里，<code>int</code> 是数组元素的类型，<code>numbers</code> 是数组的名称，<code>5</code> 是数组的大小，表示这个数组可以存放 5 个整数。事实上，我们可以将数组中的每个元素看作是一个简单变量。</p><h2 id="411-初始化数组"></a> 4.1.1 初始化数组</h2><p>C++ 初始化数组有几条规则，他们限制了初始化的时刻，决定了数组元素数目与初始化器中值的数目不相同时将发生的情况。</p><p>只有在定义数组时才能使用初始化，此后就不能再初始化了，也不能将一个数组赋给另外一个数组（但可以使用索引分别给数组元素赋值）：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 允许</span></span><br><span class="line"><span class="type">int</span> arr1[<span class="number">3</span>] = &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 允许</span></span><br><span class="line"><span class="type">int</span> arr2[<span class="number">3</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 允许</span></span><br><span class="line"><span class="type">int</span> number = <span class="number">2</span>;</span><br><span class="line"><span class="type">int</span> arr3[<span class="number">3</span>];</span><br><span class="line">arr3[<span class="number">3</span>] = number;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 不允许</span></span><br><span class="line"><span class="type">int</span> arr4[<span class="number">3</span>];</span><br><span class="line">arr4[<span class="number">3</span>] = &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>&#125; </span><br><span class="line"></span><br><span class="line"><span class="comment">// 不允许</span></span><br><span class="line">arr1 = arr2;</span><br></pre></td></tr></table></figure><p>有几种常见的初始化数组的方式：</p><p><strong>全部初始化</strong>：在声明数组时，为所有元素提供初始值。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> numbers[<span class="number">5</span>] = &#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>&#125;;</span><br></pre></td></tr></table></figure><p><strong>部分初始化</strong>：只提供部分元素的初始值，剩下的元素会自动初始化为 0。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> numbers[<span class="number">5</span>] = &#123;<span class="number">1</span>, <span class="number">2</span>&#125;;</span><br></pre></td></tr></table></figure><p>此时，<code>numbers[0]</code> 为 1，<code>numbers[1]</code> 为 2，而 <code>numbers[2]</code>、<code>numbers[3]</code>、<code>numbers[4]</code> 都为 0。</p><p><strong>省略数组大小</strong>：如果在初始化时提供了所有元素的值，可以省略数组大小，编译器会根据初始化的值的数量来确定数组的大小。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> numbers[] = &#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>&#125;;</span><br></pre></td></tr></table></figure><p>这里，数组 <code>numbers</code> 的大小会被编译器自动确定为 5。</p><h2 id="412-访问数组元素"></a> 4.1.2 访问数组元素</h2><p>程序代码4-1（酒店房间预订程序）中说明了数组的一些属性，包括初始化数组、声明数组以及给数组元素赋值。</p><div class="note info modern"><p>之前提到三元运算符，也称为条件运算符，是 C++ 中唯一的一个三目运算符，它提供了一种简洁的条件判断和赋值方式。三元运算符的基本语法结构如下：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">condition ? expression1 : expression2;</span><br></pre></td></tr></table></figure><p><strong>condition</strong>：这是一个布尔表达式，也就是一个其结果要么为 true 要么为 false 的表达式。它用于进行条件判断，是整个三元运算符的判断依据。</p><p><strong>expression1</strong>：当 condition 的结果为 true 时，整个三元运算符表达式的结果就是 expression1 的值。</p><p><strong>expression2</strong>：当 condition 的结果为 false 时，整个三元运算符表达式的结果就是 expression2 的值。</p><p>简而言之，<code>condition</code> 为真吗？如果为真返回 <code>expression1</code> 否则就返回 <code>expression2</code>。</p></div><figure class="highlight c++"><figcaption><span>程序代码4-1(酒店房间预订程序)</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 定义布尔数组来表示 3 个房间的使用状态，初始都为空闲</span></span><br><span class="line">    <span class="type">bool</span> roomStatus[<span class="number">3</span>] = &#123;<span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 显示房间初始状态</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;房间 1：&quot;</span> &lt;&lt; (roomStatus[<span class="number">0</span>] ? <span class="string">&quot;已使用&quot;</span> : <span class="string">&quot;空闲&quot;</span>) &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;房间 2：&quot;</span> &lt;&lt; (roomStatus[<span class="number">1</span>] ? <span class="string">&quot;已使用&quot;</span> : <span class="string">&quot;空闲&quot;</span>) &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;房间 3：&quot;</span> &lt;&lt; (roomStatus[<span class="number">2</span>] ? <span class="string">&quot;已使用&quot;</span> : <span class="string">&quot;空闲&quot;</span>) &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 模拟预订房间 2</span></span><br><span class="line">    roomStatus[<span class="number">1</span>] = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 显示房间更新后的状态</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;\n更新后：&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;房间 1：&quot;</span> &lt;&lt; (roomStatus[<span class="number">0</span>] ? <span class="string">&quot;已使用&quot;</span> : <span class="string">&quot;空闲&quot;</span>) &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;房间 2：&quot;</span> &lt;&lt; (roomStatus[<span class="number">1</span>] ? <span class="string">&quot;已使用&quot;</span> : <span class="string">&quot;空闲&quot;</span>) &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;房间 3：&quot;</span> &lt;&lt; (roomStatus[<span class="number">2</span>] ? <span class="string">&quot;已使用&quot;</span> : <span class="string">&quot;空闲&quot;</span>) &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>下面是程序的运行结果：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">房间 1：空闲</span><br><span class="line">房间 2：空闲</span><br><span class="line">房间 3：空闲</span><br><span class="line"></span><br><span class="line">更新后：</span><br><span class="line">房间 1：空闲</span><br><span class="line">房间 2：已使用</span><br><span class="line">房间 3：空闲</span><br></pre></td></tr></table></figure><div class="animation-figure" markdown><p><img src="/images/hellocpp/img_4/4-1-1Arrays.jpg" alt="Arrays" /></p></div><p align="center"> 图 4-1-1 &nbsp; 数组下标 </p><p><strong>数组的索引是从 0 开始的</strong>。也就是说，对于一个大小为 n 的数组，合法的索引范围是从 0 到 n - 1。例如程序代码4-1（酒店房间预订程序）中我们使用 <code>roomStatus[1] = true;</code> 语句将房间 2 由空闲变为已使用状态。<strong>你可以像使用普通变量一样使用数组元素，比如进行赋值、计算等操作</strong>。</p><div class="note warning modern"><p>务必注意：</p><p>目前大多数市面上的 C++ 编译器并不会主动检查使用的下标是否合法有效。<br />如果将一个值赋一个不存在的元素，例如：<code>array[666]</code>，编译器并不会报错，但程序运行后，可能会导致程序异常终止。所以请务必注意确保使用有效的下标值。</p></div><h2 id="413-多维数组"></a> 4.1.3 多维数组</h2><p>除了一维数组，还有多维数组，最常见的是二维数组。二维数组可以想象成一个表格，有行和列。声明二维数组的格式如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">数据类型 数组名[行数][列数];</span><br></pre></td></tr></table></figure><p>例如，我们声明一个 5 行 4 列的整数二维数组，并使其初始化：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//声明一个二维数组</span></span><br><span class="line"><span class="type">int</span> matrix[<span class="number">5</span>][<span class="number">4</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">//对二维数组进行初始化</span></span><br><span class="line"><span class="type">int</span> matrix[<span class="number">5</span>][<span class="number">4</span>] =</span><br><span class="line">&#123;</span><br><span class="line">    &#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>&#125;,</span><br><span class="line">    &#123;<span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>&#125;,</span><br><span class="line">    &#123;<span class="number">9</span>, <span class="number">10</span>, <span class="number">11</span>, <span class="number">12</span>&#125;</span><br><span class="line">    &#123;<span class="number">13</span>, <span class="number">14</span>, <span class="number">15</span>, <span class="number">16</span>&#125;</span><br><span class="line">    &#123;<span class="number">17</span>, <span class="number">18</span>, <span class="number">19</span>, <span class="number">20</span>&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>访问二维数组的元素需要指定行索引和列索引，例如 <code>matrix[1][2]</code> 表示第二行第三列的元素，值为 7。</p><h2 id="414-数组的替代品"></a> 4.1.4 数组的替代品</h2><p>C++ 标准模板库（STL）中有一种数组的替代品—— vector，它比复合类型数组更复杂也更灵活，好虽好但也请不要着急，我们还在后续章节向你详细介绍 STL 和 模板类 vector。</p><div class="note info modern"><p>依靠编译器计算元素个数</p><p>在某些情况下，若依靠编译器来自动确定数组元素的个数，可能会产生不符合预期的结果。这是因为编译器的计算逻辑是基于它所看到的数据来进行的，当代码存在一些特殊情况或者开发者对数组的操作和设想与编译器的理解不一致时，就会导致计算出的元素个数和开发者原本设想的不同。</p><p>例如，当你将一个数组传递给函数时，数组名会退化为指针，此时如果在函数内部使用某些方式尝试让编译器计算数组元素个数，就会得到错误的结果，因为指针本身并不包含数组大小的信息。</p><p>但这种方法对于将字符数组初始化为一个字符串来说比较安全，当使用字符串常量来初始化字符数组时，编译器会正确处理字符串末尾的空字符 ‘\0’。</p><p><strong>在这里我介绍一种计算数组元素个数的方法。</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> array[] = &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>&#125;;</span><br><span class="line"><span class="type">int</span> num_elements = <span class="keyword">sizeof</span> array / <span class="built_in">sizeof</span>(array);</span><br></pre></td></tr></table></figure><p><code>sizeof</code> 它可以返回一个变量或者类型所占用的字节数。<code>sizeof array</code> 会返回整个数组 <code>array</code> 所占用的字节数，<code>sizeof(short)</code> 会返回 <code>short</code> 类型所占用的字节数。将整个数组的字节数除以单个元素的字节数，就可以得到数组中元素的个数。</p><p>如果在编写代码时，数组元素个数可能会经常变动，使用这种方式可以避免手动修改元素个数的代码，提高代码的可维护性，这就是很有必要的；</p></div><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>正整数常数：正整数常数指的是大于 0 的整数，常数是具有固定值的量（如 const 常量），其值不会发生变化。也就是说，在指定数组元素数目时我们必须将其指定为大于 0 且不可以是变量（不过，一些编译器（如 GCC）支持可变长度数组（VLA）作为扩展特性，但这并非 C++ 标准的一部分）。本章节后续会介绍如何使用 <code>new</code> 操作符来规避这种限制。 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">本文是C++数组的零基础入门指南。详解数组的声明、初始化、访问及多维数组使用，并通过酒店预订系统等实战案例帮助理解。适合初学者打好数据结构基础。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》第 4 章 复合类型</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4_CompositeTypes/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/4_CompositeTypes/</id>
    <published>2025-11-23T14:49:20.000Z</published>
    <updated>2025-11-23T14:49:20.000Z</updated>
    
    <content type="html"><![CDATA[<div class="note blue anzhiyufont anzhiyu-icon-sanmingzhi flat"><ul><li>如何创建和使用数组；</li><li>如何创建和使用 C 风格的字符串；</li><li>如何创建和使用 <code>string</code> 类的字符串；</li><li>如何混合输入字符串和数字；</li><li>如何使用 <code>getline()</code> 和 <code>get()</code> 方法来读取字符串；</li><li>如何创建和使用结构；</li><li>如何创建和使用共用体；</li><li>如何创建和使用枚举；</li><li>如何创建和使用指针；</li><li>如何管理动态内存；</li><li>如何创建和使用动态数组；</li><li>如何创建动态结构；</li><li>了解自动存储、静态存储和动态存储。</li></ul></div><p>嘿，恭喜你，一路披荆斩棘的离开了数据操作的奇妙森林，很高兴看到你用基本数据类型和各种运算符玩得那叫一个不亦乐乎，就像熟练的厨师在厨房里摆弄着锅碗瓢盆，做出了一道道简单却美味的数据“菜肴”。</p><p>但请不要以为编程的冒险就到此为止啦！现在，咱们要一脚迈进第 4 章复合类型这个神秘又刺激的全新世界。如果说第 3 章的基本数据类型是一个个孤零零的小士兵，那这章的复合类型就是由它们组成的强大军团，有能批量收纳数据的数组“大仓库”，有像超级导航一样精准定位的指针，还有和变量亲密无间的引用“好兄弟”。</p><p>更厉害的是，这里还有 <code>new</code> 和 <code>delete</code> 这对神奇搭档，能像魔法师一样在程序运行时随意召唤和遣散内存空间，打造出各种动态结构和数组。这就好比咱们从操控小士兵升级成了指挥千军万马的大将军，能构建出更加宏伟壮观的编程城堡！</p><p>准备好了吗？让咱们一起撸起袖子，在复合类型的世界里大干一场，创造出属于咱们的编程传奇！</p>]]></content>
    
    
    <summary type="html">本章学习C++数组的声明、初始化及使用。掌握如何安全存储和访问同类型数据集合，了解C++11列表初始化等现代用法。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.10 章节总结</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-10_Summary/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-10_Summary/</id>
    <published>2025-11-20T08:00:55.000Z</published>
    <updated>2025-12-04T06:39:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>嘿呀，本章可真是把 C++ 里数据操作的“十八般武艺”都亮出来啦！就好比一场精彩的表演，先是简单变量闪亮登场，它们就像一群活泼的小精灵，各自有着不同的性格（数据类型），在内存的舞台上尽情玩耍。接着，<code>const</code> 常量限定符如同一位严格的“纪律委员”，给那些喜欢乱动的变量套上了“紧箍咒”，让它们的值乖乖保持不变。</p><p>再瞧瞧浮点类型，这就像是一群调皮的魔法师，能表示带小数的数值。不过呢，它们也有点小脾气，在运算的时候容易产生舍入误差，就像魔法师偶尔也会念错咒语一样，所以和它们打交道可得多留个心眼。</p><p>算术操作符就像是神奇的魔法棒，<code>+</code>、<code>-</code>、<code>*</code>、<code>/</code>、<code>%</code> 这些符号一挥，数据就能进行各种奇妙的变化。但它们也有自己的“江湖规矩”，优先级和结合性就是它们的“辈分”和“规矩”，可不能乱了套。</p><p>操作符重载更像是一场创意十足的变装派对，我们可以为自定义类型重新设计操作符的行为，让它们也能像内置类型一样在派对上欢快地“跳舞”。不过，可不能玩得太疯，得遵循操作符的原有“风格”，不然派对可就乱成一锅粥。</p><p>最后，类型转换就像是一个神奇的“变形金刚”，能让数据在不同的形态之间自由转换。隐式类型转换就像偷偷摸摸的小变身，编译器会自动帮我们完成；而显式类型转换则像是一场盛大的公开表演，需要我们亲自指定转换的类型。</p><p>掌握了这些知识，咱就像拥有了一把万能钥匙，能更加灵活地打开不同类型数据的“宝箱”，编写出高效、安全又好维护的 C++ 程序。在实际编程的江湖里闯荡时，可得根据具体的“战斗需求”，挑选合适的数据类型、操作符和类型转换方式，时刻留意各种操作里的小陷阱，比如浮点运算的误差、操作符重载的合理性，不然一不小心就会掉进“坑”里，摔得鼻青脸肿哟！</p>]]></content>
    
    
    <summary type="html">本章节是C++初学者的数据处理完全指南，详细讲解变量、常量、整型、浮点型等基本数据类型，深入剖析算术运算符、自增自减、赋值运算的优先级与用法，并涵盖C++11新特性如auto类型推断和初始化列表。助你灵活操作数据，编写高效安全的C++代码。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.9 衰变复制(选读)</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-9_DecayCopy/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-9_DecayCopy/</id>
    <published>2025-11-19T07:30:00.000Z</published>
    <updated>2025-11-19T07:30:00.000Z</updated>
    
    <content type="html"><![CDATA[<div class="note info modern"><p>章节阅读提示</p><p>在学习 C++ 的过程中，<strong>衰变复制（Decay Copy）是一个与语言最新发展密切相关的进阶特性</strong>。它作为 C++ 23 引入的新特性，结合了类型推导、模板编程和值语义等多项复杂概念。建议初学 C++ 的读者将本小节作为日后工作中的工具文献阅读，在初学阶段你大可不必理会本小节。以下为系统性学习建议：</p><p><strong>现阶段建议</strong><br /><strong>目前先跳过衰变复制这部分内容的学习。因为衰变复制涉及到 std::decay 类型特性、auto 关键字的高级用法、值类别（左值/右值）等较为深入的知识，需要一定的基础才能完全理解。而你当前的知识储备可能还不足以完全掌握它。过早接触可能会让你感到困惑，影响学习的积极性和效果。</strong></p><p><strong>后续学习指引</strong><br />当你完成以下几个关键部分的学习后，就可以返回阅读操作符重载这一小节了：</p><ol><li><strong>C++ 模板基础</strong></li><li><strong>auto 关键字</strong></li><li><strong>值类别（Value Categories）</strong></li><li><strong>拷贝构造函数与移动构造函数</strong></li><li><strong>标准库类型特性</strong></li></ol><p>当你完成上述内容的学习后，你将具备足够的知识基础来深入学习衰变复制。此时再返回阅读衰变复制这部分内容，你会发现理解起来更加轻松，也能更好地掌握这一 C++ 新特性。</p></div><p>C++23 中引入的衰变复制 (Decay Copy) 是一个旨在简化对象副本创建过程的语言特性。它通过 <code>auto(x)</code> 和 <code>auto&#123;x&#125;</code> 这两种新语法，为开发者提供了一种更为简洁和安全的方式来生成对象的右值副本，尤其在模板编程和并发编程中非常有用。</p><h2 id="391-什么是衰变复制"></a> 3.9.1 什么是衰变复制</h2><p>你可以将衰变复制理解为是一种组合操作，它主要包含两个连续的步骤：</p><ol><li><strong>第一步是类型衰变</strong>。这一步借鉴了 C++ 模板中对传值参数进行类型推导的规则，它会处理掉类型中的引用限定符（<code>&amp;</code> 和 <code>&amp;&amp;</code>）以及顶层的 const/volatile 限定符。同时，它也会将数组类型转换为对应的指针类型，将函数类型转换为函数指针类型。例如，<code>const char</code> 会衰变为 <code>const char*</code>，<code>int (&amp;)()</code> 会衰变为 <code>int (*)()</code>。</li><li><strong>第二步是创建副本</strong>。在类型衰变之后，会基于衰变后的类型创建一个新的对象副本。如果原始表达式是左值，则调用拷贝构造函数；如果是右值，则优先调用移动构造函数。最终，auto(x) 或 auto{x} 表达式会产生一个纯右值，代表这个新创建的临时对象。</li></ol><h2 id="392-为什么需要衰变复制"></a> 3.9.2 为什么需要衰变复制</h2><p>在 C++23 引入衰变复制之前，在泛型代码中安全、高效地创建一个对象的副本有时会有些棘手。首先，当你在模板函数中，面对一个由模板参数推导出的复杂类型 T，想要声明一个该类型的变量来存储副本，类型书写可能很繁琐，甚至可能因为类型不匹配而导致错误。</p><p>其次，有些类的拷贝构造函数被声明为 explicit。这意味着你不能直接使用类似 <code>T copy = original;</code> 的语法进行拷贝初始化，这增加了代码编写的难度。</p><p>此外，在 C++11 标准制定过程中，标准库工作组遇到了一个具体问题。例如，在使用 std::thread 构造函数并传递字符串字面量时，字符串字面量的类型是数组（例如 const char），而数组是不可复制、不可移动的，这会导致编译错误。虽然可以通过将参数改为传值方式利用类型衰变来解决匹配问题，但又可能引入不必要的性能开销。衰变复制的概念正是为了优雅地解决这类问题而提出的。</p><h2 id="393-衰变复制的语法和应用场景"></a> 3.9.3 衰变复制的语法和应用场景</h2><p>在 C++23 中，衰变复制通过 auto(x) 和 auto{x} 表达式实现。这两种语法形式在功能上是完全等价的，它们都会执行衰变复制并生成一个右值副本。选择使用圆括号 auto(x) 还是花括号 auto{x}，通常可以根据个人或团队的编码风格来决定，花括号初始化一般能提供更严格的类型检查。</p><p>需要特别注意的是，auto 在这里的用法与变量声明中的类型推导不同。auto(x) 是一个独立的表达式，它可以在任何需要表达式的地方使用，其含义是“创建 x 的一个衰变副本”</p><h3 id="模板编程中的副本创建"></a> 模板编程中的副本创建</h3><p>在模板函数中，当你需要创建一个参数的副本而又不确切知道或不关心其具体类型时，auto(x) 非常有用。它简化了代码，也避免了因类型书写错误而可能带来的问题。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">processValue</span><span class="params">(T&amp;&amp; param)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 使用 auto(param) 创建 param 的衰变副本</span></span><br><span class="line">    <span class="keyword">auto</span> decayed_copy = <span class="built_in">auto</span>(param);</span><br><span class="line">    <span class="comment">// ... 对 decayed_copy 进行操作，不会影响原始 param</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="避免容器操作导致的引用失效"></a> 避免容器操作导致的引用失效</h3><p>在处理容器时，如果你持有了容器中某个元素的引用，随后对容器进行了修改操作，这个引用可能会失效。使用 auto(x) 可以先创建元素的副本，从而安全地操作。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> Container&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">safeModificationTest</span><span class="params">(Container&amp; c)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (!c.<span class="built_in">empty</span>())</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">auto</span> element_copy = <span class="built_in">auto</span>(c.<span class="built_in">front</span>());    <span class="comment">// 创建首元素副本</span></span><br><span class="line">        c.<span class="built_in">clear</span>();                              <span class="comment">// 即使清空容器，副本仍然有效</span></span><br><span class="line">        <span class="comment">// 可以安全地使用 element_copy</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="并发编程中传递参数"></a> 并发编程中传递参数</h3><p>在启动新线程时，需要确保传递给线程函数的参数是独立的副本，以避免数据竞争。auto(x) 可以明确地表示创建副本。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">backgroundTaskTest</span><span class="params">(<span class="type">const</span> std::string&amp; data)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 明确创建 data 的副本传递给新线程</span></span><br><span class="line">    <span class="function">std::jthread <span class="title">worker</span><span class="params">([](std::string safe_data)</span></span></span><br><span class="line"><span class="params"><span class="function">    &#123;</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="comment">// 在新线程中安全地使用 safe_data</span></span></span></span><br><span class="line"><span class="params"><span class="function">    &#125;, <span class="keyword">auto</span>(data))</span></span>; <span class="comment">// 使用 auto(data) 创建副本</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="需要纯右值的上下文"></a> 需要纯右值的上下文</h3><p>在某些时候，例如 return 语句或需要将对象作为纯右值传递时，auto(x) 可以方便地生成所需的表达式。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Widget</span></span><br><span class="line">&#123;</span><br><span class="line">    std::vector&lt;<span class="type">int</span>&gt; data;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">// 返回 data 的衰变副本（右值）</span></span><br><span class="line">    <span class="function"><span class="keyword">auto</span> <span class="title">getDataCopy</span><span class="params">()</span> <span class="type">const</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">auto</span>(data);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="394-性能影响"></a> 3.9.4 性能影响</h2><p>虽然衰变复制带来了便利，但我们也需要关注其性能影响。</p><p>最核心的一点是，auto(x) 在 x 本身已经是一个纯右值（prvalue）时，编译器可能会进行优化，避免产生不必要的复制操作。然而，如果 x 是左值，则确实会发生一次拷贝操作。因此，<strong>在性能敏感的代码中，需要谨慎使用，你需要确保副本的创建是绝对必要的</strong>。</p><p>与传统的显式写类型创建副本（如 <code>T copy = original;</code> ）或使用 std::decay 结合 decltype 的方式相比，auto(x) 在语法上更加简洁直观，并且可能带来更好的优化机会。</p>]]></content>
    
    
    <summary type="html">深入解析C++23新特性衰变复制（Decay Copy），详解auto(x)和auto{x}语法如何简化对象副本创建，涵盖其类型衰变机制、在模板编程、避免引用失效和并发编程中的核心应用场景、性能考量及最佳实践，助你掌握现代C++高效编程技巧。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.8 auto 自动类型推导</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-8_TypeDeduction/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-8_TypeDeduction/</id>
    <published>2025-11-18T13:30:00.000Z</published>
    <updated>2025-11-24T15:20:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>你还记得吗？我们曾在 <a href="/bookHelloCpp/HelloCpp/3-1_SimpleVariables">3.1 简单变量及类型</a>和 <a href="/bookHelloCpp/HelloCpp/3-3_FloatingPointTypes">3.3浮点类型</a>中介绍了大量的变量类型。事实上通过后续学习你会发现还有更多更复杂的类型等着你去学习，甚至你还会认识到较为特殊的匿名类型。这一些列类型组成了 C++ 庞大且复杂的类型系统，而面对类型日益复杂化带来的编码负担，C++ 11 引入了 <code>auto</code> 类型推导，这一举措既提升了代码的编写效率和安全性又提升了代码的可维护性。</p><p>在 C++ 11 之前的版本中，定义变量或者声明变量之前都必须指明它的类型，但在 C++ 11 中，编译器可以自主去介入推导类型了，这就使得 C++ 的代码编写更加方便和安全。在之前的 C++ 版本中，auto 关键字用来存储类型说明符，显式声明变量的存储期，这其实相当冗余鸡肋。因为局部变量<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>默认就是自动存储期，显式添加 auto(<code>auto int a</code>) 与直接写 <code>int a</code> 本质上没有任何区别。由于是默认行为，显式声明就显得有点多此一举了。</p><p>而 C++11 移除了 auto 关键字自动存储期的含义，并赋予 auto 关键字新的作用 —— 自动类型推导。也就是说，使用了 auto 关键字以后，编译器会在编译期间自动推导出变量的类型，这样我们就不需要手动指明变量的数据类型了。下面是一个简单的示例：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> a = <span class="number">20</span>;                            <span class="comment">// a 是 int 类型</span></span><br><span class="line"><span class="keyword">auto</span> b = <span class="number">20.25</span>;                         <span class="comment">// b 是 double 类型</span></span><br><span class="line"><span class="keyword">auto</span> c = <span class="number">1.9L</span>;                          <span class="comment">// c 是 long double 类型</span></span><br><span class="line"><span class="keyword">auto</span> d = <span class="string">&quot;https://blog.yujiay.wang/&quot;</span>;   <span class="comment">// d 是 const char* 类型, which is the author&#x27;s blog homepage URL</span></span><br></pre></td></tr></table></figure><ul><li>第 1 行中：20 是一个整数，默认是 int 类型，所以推导出来的变量 a 类型是 int 型；</li><li>第 2 行中：20.25 是一个小数，默认是 double 类型，所以推导出来的变量 b 类型是 double 型；</li><li>第 3 行中：1.9L 是一个小数，后缀 L 表示 long double 类型，所以推导出来的变量 c 类型是 long double 型；</li><li>第 4 行中：“<a href="https://blog.yujiay.wang/">https://blog.yujiay.wang/</a>” 是一个字符串字面量，在 C++ 中类型是 const char*<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>，所以推导出来的变量 d 类型是 const char* 型；</li></ul><p>介绍到这里，肯定有同学想了，auto 太棒了，不需要在人为再去记忆那么多复杂的类型了，一个 auto 不就可以搞定一切了吗？错的同学错的。自动类型推导并不是为了这种简单情况而设计的，让你心寒了。事实上，如果将其用于这种简单的情况，反而可能得不偿失。例如，你需要将某一人的身高（单位为厘米）存为 double 类型，以便后续程序中与米制单位进行转换，你使用了如下代码：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> height = <span class="number">183</span>;</span><br></pre></td></tr></table></figure><p>程序将直接将 height 变量推导成 int 类型的 183，而不是我们期待的 double 183.0 。显式的声明类型时，将变量初始化为 double 183 不会造成任何问题，但自动类型推导可能会造成难以排查大问题便得不偿失。</p><p>auto 只有在处理复杂类型时，比如用来定义标准模板库（STL）中的迭代器时（标准模板库及迭代器会在第十四章进行详细介绍，这里只是为了演示 auto 关键字的正确使用时机，不必死磕代码），需要使用迭代器遍历容器中的元素，不同容器的迭代器有不同的类型，在定义迭代器时必须要指明。而迭代器的类型有时候比较复杂，书写起来也很麻烦，我们便可以借助自动类型推导进行简化。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; v;</span><br><span class="line">    vector&lt;vector&lt;<span class="type">int</span>&gt;&gt;::iterator i = v.<span class="built_in">begin</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>不难发现，定义迭代器 i 时，类型写起来很长，而且还容易出错，但是借助 auto 自动类型推导，我们可以进行重写，让其更简洁：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; v;</span><br><span class="line">    <span class="keyword">auto</span> i = v.<span class="built_in">begin</span>();     <span class="comment">// 使用 auto 关键字进行自动类型推导</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div class="note warning modern"><p>这里我们需要注意，使用 auto 自动类型推导的变量<strong>必须马上初始化</strong>。这点很容易解释，因为 auto 关键字只是“占位符”，并非如 int、double 等关键字是真正的类型声明。</p></div><p>通过以上学习，相信你已经掌握了 auto 自动类型推导，在后续的学习过程中，我们会带领大家通过 auto 关键字优化我们的程序。</p><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>局部变量是定义在函数内部的变量，它们的作用域仅限于函数内部。这意味着，一旦离开了定义它们的函数，这些变量就无法被访问或使用了。局部变量在函数被调用时分配内存，并在函数调用结束后立即释放内存。 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>C++ 中，在类型后面加上星号（*），通常用于声明一个指针变量。这个指针变量存储的是另一个变量或对象的内存地址，而不是数据值本身。现在的你请别担心如何使用指针，指针是 C++ 庞大且复杂的内容，我们会在第四章 4.3 小节详细学习。 <a href="#fnref2" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">C++11 auto关键字彻底改变了类型声明方式，让编译器自动推导变量类型。本文深入解析auto的类型推导原理、核心使用场景（如简化STL迭代器、范围for循环）、注意事项，并对比C++14/17的扩展特性，帮助开发者编写更简洁、安全的现代C++代码。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>安知鱼主题细节美化及实用教程</title>
    <link href="https://blog.yujiay.wang/tech/techPractice/SpecialEffects/"/>
    <id>https://blog.yujiay.wang/tech/techPractice/SpecialEffects/</id>
    <published>2025-11-18T11:10:12.000Z</published>
    <updated>2026-02-03T14:07:15.000Z</updated>
    
    <content type="html"><![CDATA[<p>这篇文章是一篇教学文章，在我的网站进行新升级后我会在这里长期更新我所实现的效果。如果你有问题可以在文章末尾的评论区进行提问，我会尽快回复。</p><div class="note warning flat"><p>请注意，当你改动任何配置文件前请务必进行备份操作，这是一种保障也是一个良好的运维习惯。</p></div><h2 id="1页脚添加备案号"></a> 1.页脚添加备案号</h2><h3 id="10-效果图"></a> 1.0 效果图</h3><p><img src="/images/2025/19/footer.png" alt="footer_image" /></p><h3 id="11-添加-_configyml-字段"></a> 1.1 添加 _config.yml 字段</h3><p>在博客根目录 Hexo 的配置文件(_config.yml)中添加如下新键值（<strong>这里要注意，是 Hexo 的配置文件，不是安知鱼主题的配置文件！</strong>）：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#建议添加在 timezone 下面，你也可以添加在其他位置</span></span><br><span class="line"><span class="attr">icp:</span> <span class="string">填写</span> <span class="string">ICP</span> <span class="string">备案号</span></span><br><span class="line"><span class="attr">gb:</span> <span class="string">填写公网安备号</span></span><br></pre></td></tr></table></figure><h3 id="12-添加-引用-css"></a> 1.2 添加、引用 CSS</h3><p>完成了第 1 步后我们需要为页脚容器进行样式定义。在博客的 <code>/source/</code> 目录中的 <code>css</code> 文件夹中创建一个名为 <code>coustom.css</code> 的文件（如果你没有 <code>css</code> 文件夹可以自行创建一个）。</p><p>在新建的 <code>custom.css</code> 文件中添加如下代码：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*============================= 页脚备案容器开始 blog.yujiay.wang =============================*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 为 #footer-bar 设置相对定位，作为备案容器的定位参考 */</span></span><br><span class="line"><span class="selector-id">#footer-bar</span> &#123;</span><br><span class="line">    <span class="comment">/* 为备案信息预留更多空间 */</span></span><br><span class="line">    <span class="attribute">min-height</span>: <span class="number">100px</span>;</span><br><span class="line">    <span class="comment">/* 底部内边距，确保有足够空间 */</span></span><br><span class="line">    <span class="attribute">padding-bottom</span>: <span class="number">50px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 备案链接容器样式 - 使用ID选择器 */</span></span><br><span class="line"><span class="selector-id">#beian-links</span> &#123;</span><br><span class="line">    <span class="comment">/* 定位样式 - 绝对定位在 footer-bar 底部居中 */</span></span><br><span class="line">    <span class="attribute">position</span>: absolute;</span><br><span class="line">    <span class="attribute">bottom</span>: <span class="number">15px</span>;</span><br><span class="line">    <span class="attribute">left</span>: <span class="number">50%</span>;</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">translateX</span>(-<span class="number">50%</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 文本和布局样式 */</span></span><br><span class="line">    <span class="attribute">display</span>: block;</span><br><span class="line">    <span class="attribute">width</span>: auto;</span><br><span class="line">    <span class="attribute">text-align</span>: center;</span><br><span class="line">    <span class="attribute">white-space</span>: nowrap;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 字体样式 */</span></span><br><span class="line">    <span class="attribute">font-size</span>: <span class="number">12px</span>;</span><br><span class="line">    <span class="attribute">color</span>: <span class="built_in">var</span>(--anzhiyu-fontcolor);</span><br><span class="line">    <span class="attribute">line-height</span>: <span class="number">1.5</span>;</span><br><span class="line">    <span class="attribute">font-family</span>: -apple-system, BlinkMacSystemFont, <span class="string">&quot;Segoe UI&quot;</span>, Roboto, sans-serif;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* 确保在最上层 */</span></span><br><span class="line">    <span class="attribute">z-index</span>: <span class="number">10</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 备案链接的样式 */</span></span><br><span class="line"><span class="selector-id">#beian-links</span> <span class="selector-tag">a</span><span class="selector-class">.footer-bar-link</span> &#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="built_in">var</span>(--anzhiyu-fontcolor); <span class="comment">/* 链接文字也设置为深色 */</span></span><br><span class="line">    <span class="attribute">text-decoration</span>: none;</span><br><span class="line">    <span class="attribute">transition</span>: color <span class="number">0.3s</span> ease; <span class="comment">/* 添加过渡效果 */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#beian-links</span> <span class="selector-tag">a</span><span class="selector-class">.footer-bar-link</span><span class="selector-pseudo">:hover</span> &#123;</span><br><span class="line">    <span class="attribute">text-decoration</span>: none;</span><br><span class="line">    <span class="attribute">color</span>: <span class="built_in">var</span>(--anzhiyu-lighttext); <span class="comment">/* 悬停颜色 */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 移动端适配 */</span></span><br><span class="line"><span class="keyword">@media</span> (<span class="attribute">max-width</span>: <span class="number">768px</span>) &#123;</span><br><span class="line">    <span class="selector-id">#beian-links</span> &#123;</span><br><span class="line">        <span class="attribute">margin</span>: -<span class="number">30px</span> <span class="number">0</span>;</span><br><span class="line">        <span class="attribute">font-size</span>: <span class="number">11px</span>;</span><br><span class="line">        <span class="attribute">white-space</span>: normal; <span class="comment">/* 允许内容换行 */</span></span><br><span class="line">        <span class="attribute">text-align</span>: center; <span class="comment">/* 确保换行后内容依然居中 */</span></span><br><span class="line">        <span class="attribute">max-width</span>: <span class="number">90%</span>;</span><br><span class="line">        <span class="attribute">bottom</span>: <span class="number">10px</span>;</span><br><span class="line">        <span class="comment">/* 使整个容器在移动端独占一行，居中效果更稳定 */</span></span><br><span class="line">        <span class="attribute">display</span>: block;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="selector-id">#beian-links</span> <span class="selector-tag">a</span><span class="selector-class">.footer-bar-link</span> &#123;</span><br><span class="line">        <span class="attribute">display</span>: inline-block;</span><br><span class="line">        <span class="attribute">line-height</span>: <span class="number">1.8</span>;</span><br><span class="line">        <span class="attribute">padding</span>: <span class="number">2px</span> <span class="number">4px</span>;</span><br><span class="line">        <span class="comment">/* 单独成行，可以设置为 block，并赋予宽度或使用其他布局 */</span></span><br><span class="line">        <span class="comment">/* display: block; */</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">     <span class="comment">/* 移动端适配链接样式 */</span></span><br><span class="line">    <span class="selector-id">#beian-links</span> <span class="selector-class">.separator</span> &#123;</span><br><span class="line">            <span class="attribute">display</span>: none <span class="meta">!important</span>; <span class="comment">/* 上下排列时隐藏竖线分隔符 */</span></span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 暗色模式适配 */</span></span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#beian-links</span> <span class="selector-tag">a</span><span class="selector-class">.footer-bar-link</span> &#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="built_in">var</span>(--anzhiyu-fontcolor);;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#beian-links</span> <span class="selector-tag">a</span><span class="selector-class">.footer-bar-link</span><span class="selector-pseudo">:hover</span> &#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="built_in">var</span>(--anzhiyu-lighttext);</span><br><span class="line">    <span class="attribute">text-decoration</span>: none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 竖线分隔符样式 */</span></span><br><span class="line"><span class="selector-id">#beian-links</span> <span class="selector-class">.separator</span> &#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="number">#CCCCCC</span>;</span><br><span class="line">    <span class="attribute">margin</span>: <span class="number">0</span> <span class="number">10px</span>;</span><br><span class="line">    <span class="attribute">display</span>: inline-block;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 暗色模式竖线适配 */</span></span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#beian-links</span> <span class="selector-class">.separator</span> &#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="number">#666666</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*============================= 页脚备案容器结束 blog.yujiay.wang =============================*/</span></span><br></pre></td></tr></table></figure><p>添加好后记得保存修改的文件。此外还需要在<strong>安知鱼主题的配置文件</strong> <code>inject</code> -&gt; <code>head</code> 处进行自定义 css 的引入工作：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="string">&lt;link</span> <span class="string">rel=&quot;stylesheet&quot;</span> <span class="string">href=&quot;/css/custom.css&quot;&gt;</span></span><br></pre></td></tr></table></figure><h3 id="13-修改-footerpug-文件"></a> 1.3 修改 footer.pug 文件</h3><p>紧接着我们需要修改模板引擎，<strong>这里特别要注意缩进，Pug 的缩进至关重要，它直接决定了代码能否正确运行以及最终生成的HTML结构</strong>。如果你不确定缩进是否正确，最简单的办法，就是在 footer.pug 代码的最底部回车两个空行，然后将输入光标删除到最前端（没有缩进）的地方，复制下面的代码，然后将代码的第一行 <code>#footer-wrap</code> 删除掉。<strong>删除掉后不要动下面的代码，直接将空行全部删除</strong>即可。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">#footer-wrap    // 这行最后一定要删除</span><br><span class="line">    #beian-links</span><br><span class="line">        a.footer-bar-link(href=&quot;#修改为你的链接&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;)</span><br><span class="line">            img.beian-icon(src=&quot;#修改为你的图片&quot; alt=&quot;公网安备图标&quot; style=&quot;width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px;&quot;)</span><br><span class="line">            | #&#123;config.gb&#125;</span><br><span class="line">        span.separator ｜</span><br><span class="line">        a.footer-bar-link(href=&quot;https://beian.miit.gov.cn/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;)</span><br><span class="line">            img.beian-icon(src=&quot;#修改为你的图片&quot; alt=&quot;备案图标&quot; style=&quot;width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px;&quot;)</span><br><span class="line">        | #&#123;config.icp&#125;</span><br></pre></td></tr></table></figure><p>处理好缩进后我们需要将代码中的链接、图片链接进行替换，替换成为你自己的链接和图片，替换后保存。</p><h3 id="14-结束语"></a> 1.4 结束语</h3><p>最后 Hexo 三连（<code>hexo cl &amp;&amp; hexo g &amp;&amp; hexo s</code>）就可以在页面底部查看效果了，这个 css 进行了响应式适配，移动端也可以很好的展示。</p><h2 id="2添加边栏日历卡片单卡片风格"></a> 2.添加边栏日历卡片（单卡片风格）</h2><p>好久不见，I’m back，前段时间去海南出了趟差，又正好赶上大学生们的期末周，手上单子也比较多，没顾得上更新本文，今天终于忙里偷闲，回来更新一下。</p><p>今天给大家带来一个我很喜欢的边栏卡片，这个卡片我最早是借鉴一个博主的（<span class="highlighter pink">但时间太久我找不到他的原文了，希望看到能评论一下，我会链接到原文，感谢这位匿名博主</span>）。网上有很多日历小卡片，但我发现它们都是把 css 单拎出来了，这样我们就需要修改 js、css、yaml and config 四个文件了，但这次介绍这个方法只需要修改三个文件，他将 js 和 css 写到一块了，对于我来说极大的降低了维护成本，而且他的这个风格也很简约。我现在将这个方案分享给大家。</p><h3 id="20-效果图"></a> 2.0 效果图</h3><p><img src="/images/2025/19/BlogCalendarCard.png" alt="BlogCalendarCard" /></p><h3 id="21-添加-引用-javascript"></a> 2.1 添加、引用 JavaScript</h3><p>首先我们需要为日历卡片进行样式逻辑实现和样式定义。在博客的 <code>/source/</code> 目录中的 <code>js</code> 文件夹中创建一个名为 <code>countdown.js</code> 的文件（如果你没有 <code>js</code> 文件夹可以自行创建一个）。</p><p>在新建的 <code>countdown.js</code> 文件中添加以下代码（含样式实现，无需另外添加新 css 文件）：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">CountdownTimer</span> = (<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> config = &#123;</span><br><span class="line">        <span class="attr">targetDate</span>: <span class="string">&quot;2026-02-17&quot;</span>, <span class="comment">/* 这里记得每年更新春节日期 */</span></span><br><span class="line">        <span class="attr">targetName</span>: <span class="string">&quot;春节&quot;</span>,</span><br><span class="line">        <span class="attr">units</span>: &#123;</span><br><span class="line">            <span class="attr">day</span>: &#123; <span class="attr">text</span>: <span class="string">&quot;今日&quot;</span>, <span class="attr">unit</span>: <span class="string">&quot;小时&quot;</span> &#125;,</span><br><span class="line">            <span class="attr">week</span>: &#123; <span class="attr">text</span>: <span class="string">&quot;本周&quot;</span>, <span class="attr">unit</span>: <span class="string">&quot;天&quot;</span> &#125;,</span><br><span class="line">            <span class="attr">month</span>: &#123; <span class="attr">text</span>: <span class="string">&quot;本月&quot;</span>, <span class="attr">unit</span>: <span class="string">&quot;天&quot;</span> &#125;,</span><br><span class="line">            <span class="attr">year</span>: &#123; <span class="attr">text</span>: <span class="string">&quot;本年&quot;</span>, <span class="attr">unit</span>: <span class="string">&quot;天&quot;</span> &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> calculators = &#123;</span><br><span class="line">        <span class="attr">day</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> hours = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getHours</span>();</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                <span class="attr">remaining</span>: <span class="number">24</span> - hours,</span><br><span class="line">                <span class="attr">percentage</span>: (hours / <span class="number">24</span>) * <span class="number">100</span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">week</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> day = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getDay</span>();</span><br><span class="line">            <span class="keyword">const</span> passed = day === <span class="number">0</span> ? <span class="number">6</span> : day - <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                <span class="attr">remaining</span>: <span class="number">6</span> - passed,</span><br><span class="line">                <span class="attr">percentage</span>: ((passed + <span class="number">1</span>) / <span class="number">7</span>) * <span class="number">100</span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">month</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">            <span class="keyword">const</span> total = <span class="keyword">new</span> <span class="title class_">Date</span>(now.<span class="title function_">getFullYear</span>(), now.<span class="title function_">getMonth</span>() + <span class="number">1</span>, <span class="number">0</span>).<span class="title function_">getDate</span>();</span><br><span class="line">            <span class="keyword">const</span> passed = now.<span class="title function_">getDate</span>() - <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                <span class="attr">remaining</span>: total - passed,</span><br><span class="line">                <span class="attr">percentage</span>: (passed / total) * <span class="number">100</span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">year</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">            <span class="keyword">const</span> start = <span class="keyword">new</span> <span class="title class_">Date</span>(now.<span class="title function_">getFullYear</span>(), <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line">            <span class="keyword">const</span> total = <span class="number">365</span> + (now.<span class="title function_">getFullYear</span>() % <span class="number">4</span> === <span class="number">0</span> ? <span class="number">1</span> : <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">const</span> passed = <span class="title class_">Math</span>.<span class="title function_">floor</span>((now - start) / <span class="number">86400000</span>);</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                <span class="attr">remaining</span>: total - passed,</span><br><span class="line">                <span class="attr">percentage</span>: (passed / total) * <span class="number">100</span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">updateCountdown</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> elements = [<span class="string">&#x27;eventName&#x27;</span>, <span class="string">&#x27;eventDate&#x27;</span>, <span class="string">&#x27;daysUntil&#x27;</span>, <span class="string">&#x27;countRight&#x27;</span>]</span><br><span class="line">            .<span class="title function_">map</span>(<span class="function"><span class="params">id</span> =&gt;</span> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(id));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (elements.<span class="title function_">some</span>(<span class="function"><span class="params">el</span> =&gt;</span> !el)) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> [eventName, eventDate, daysUntil, countRight] = elements;</span><br><span class="line">        <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">        <span class="keyword">const</span> target = <span class="keyword">new</span> <span class="title class_">Date</span>(config.<span class="property">targetDate</span>);</span><br><span class="line"></span><br><span class="line">        eventName.<span class="property">textContent</span> = config.<span class="property">targetName</span>;</span><br><span class="line">        eventDate.<span class="property">textContent</span> = config.<span class="property">targetDate</span>;</span><br><span class="line">        daysUntil.<span class="property">textContent</span> = <span class="title class_">Math</span>.<span class="title function_">round</span>((target - now.<span class="title function_">setHours</span>(<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>)) / <span class="number">86400000</span>);</span><br><span class="line"></span><br><span class="line">        countRight.<span class="property">innerHTML</span> = <span class="title class_">Object</span>.<span class="title function_">entries</span>(config.<span class="property">units</span>)</span><br><span class="line">            .<span class="title function_">map</span>(<span class="function">(<span class="params">[key, &#123;text, unit&#125;]</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">const</span> &#123;remaining, percentage&#125; = calculators[key]();</span><br><span class="line">                <span class="keyword">return</span> <span class="string">`</span></span><br><span class="line"><span class="string">                    &lt;div class=&quot;cd-count-item&quot;&gt;</span></span><br><span class="line"><span class="string">                        &lt;div class=&quot;cd-item-name&quot;&gt;<span class="subst">$&#123;text&#125;</span>&lt;/div&gt;</span></span><br><span class="line"><span class="string">                        &lt;div class=&quot;cd-item-progress&quot;&gt;</span></span><br><span class="line"><span class="string">                            &lt;div class=&quot;cd-progress-bar&quot; style=&quot;width: <span class="subst">$&#123;percentage&#125;</span>%; opacity: <span class="subst">$&#123;percentage/<span class="number">100</span>&#125;</span>&quot;&gt;&lt;/div&gt;</span></span><br><span class="line"><span class="string">                            &lt;span class=&quot;cd-percentage <span class="subst">$&#123;percentage &gt;= <span class="number">46</span> ? <span class="string">&#x27;cd-many&#x27;</span> : <span class="string">&#x27;&#x27;</span>&#125;</span>&quot;&gt;<span class="subst">$&#123;percentage.toFixed(<span class="number">2</span>)&#125;</span>%&lt;/span&gt;</span></span><br><span class="line"><span class="string">                            &lt;span class=&quot;cd-remaining <span class="subst">$&#123;percentage &gt;= <span class="number">60</span> ? <span class="string">&#x27;cd-many&#x27;</span> : <span class="string">&#x27;&#x27;</span>&#125;</span>&quot;&gt;</span></span><br><span class="line"><span class="string">                                &lt;span class=&quot;cd-tip&quot;&gt;还剩&lt;/span&gt;<span class="subst">$&#123;remaining&#125;</span>&lt;span class=&quot;cd-tip&quot;&gt;<span class="subst">$&#123;unit&#125;</span>&lt;/span&gt;</span></span><br><span class="line"><span class="string">                            &lt;/span&gt;</span></span><br><span class="line"><span class="string">                        &lt;/div&gt;</span></span><br><span class="line"><span class="string">                    &lt;/div&gt;</span></span><br><span class="line"><span class="string">                `</span>;</span><br><span class="line">            &#125;).<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">injectStyles</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> styles = <span class="string">`</span></span><br><span class="line"><span class="string">            .card-countdown .item-content &#123;</span></span><br><span class="line"><span class="string">                display: flex;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-left &#123;</span></span><br><span class="line"><span class="string">                position: relative;</span></span><br><span class="line"><span class="string">                display: flex;</span></span><br><span class="line"><span class="string">                flex-direction: column;</span></span><br><span class="line"><span class="string">                margin-right: 0.8rem;</span></span><br><span class="line"><span class="string">                line-height: 1.5;</span></span><br><span class="line"><span class="string">                align-items: center;</span></span><br><span class="line"><span class="string">                justify-content: center;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-left .cd-text &#123;</span></span><br><span class="line"><span class="string">                font-size: 14px;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-left .cd-name &#123;</span></span><br><span class="line"><span class="string">                font-weight: bold;</span></span><br><span class="line"><span class="string">                font-size: 18px;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-left .cd-time &#123;</span></span><br><span class="line"><span class="string">                font-size: 30px;</span></span><br><span class="line"><span class="string">                font-weight: bold;</span></span><br><span class="line"><span class="string">                color: var(--anzhiyu-main);</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-left .cd-date &#123;</span></span><br><span class="line"><span class="string">                font-size: 12px;</span></span><br><span class="line"><span class="string">                opacity: 0.6;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-left::after &#123;</span></span><br><span class="line"><span class="string">                content: &quot;&quot;;</span></span><br><span class="line"><span class="string">                position: absolute;</span></span><br><span class="line"><span class="string">                right: -0.8rem;</span></span><br><span class="line"><span class="string">                width: 2px;</span></span><br><span class="line"><span class="string">                height: 80%;</span></span><br><span class="line"><span class="string">                background-color: var(--anzhiyu-main);</span></span><br><span class="line"><span class="string">                opacity: 0.5;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-right &#123;</span></span><br><span class="line"><span class="string">                flex: 1;</span></span><br><span class="line"><span class="string">                margin-left: .8rem;</span></span><br><span class="line"><span class="string">                display: flex;</span></span><br><span class="line"><span class="string">                flex-direction: column;</span></span><br><span class="line"><span class="string">                justify-content: space-between;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-count-item &#123;</span></span><br><span class="line"><span class="string">                display: flex;</span></span><br><span class="line"><span class="string">                flex-direction: row;</span></span><br><span class="line"><span class="string">                align-items: center;</span></span><br><span class="line"><span class="string">                height: 24px;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-item-name &#123;</span></span><br><span class="line"><span class="string">                font-size: 14px;</span></span><br><span class="line"><span class="string">                margin-right: 0.8rem;</span></span><br><span class="line"><span class="string">                white-space: nowrap;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-item-progress &#123;</span></span><br><span class="line"><span class="string">                position: relative;</span></span><br><span class="line"><span class="string">                display: flex;</span></span><br><span class="line"><span class="string">                flex-direction: row;</span></span><br><span class="line"><span class="string">                align-items: center;</span></span><br><span class="line"><span class="string">                justify-content: space-between;</span></span><br><span class="line"><span class="string">                height: 100%;</span></span><br><span class="line"><span class="string">                width: 100%;</span></span><br><span class="line"><span class="string">                border-radius: 8px;</span></span><br><span class="line"><span class="string">                background-color: var(--anzhiyu-background);</span></span><br><span class="line"><span class="string">                overflow: hidden;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-progress-bar &#123;</span></span><br><span class="line"><span class="string">                height: 100%;</span></span><br><span class="line"><span class="string">                border-radius: 8px;</span></span><br><span class="line"><span class="string">                background-color: var(--anzhiyu-main);</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-percentage,</span></span><br><span class="line"><span class="string">            .cd-remaining &#123;</span></span><br><span class="line"><span class="string">                position: absolute;</span></span><br><span class="line"><span class="string">                font-size: 12px;</span></span><br><span class="line"><span class="string">                margin: 0 6px;</span></span><br><span class="line"><span class="string">                transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-many &#123;</span></span><br><span class="line"><span class="string">                color: #fff;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .cd-remaining &#123;</span></span><br><span class="line"><span class="string">                opacity: 0;</span></span><br><span class="line"><span class="string">                transform: translateX(10px);</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .card-countdown .item-content:hover .cd-remaining &#123;</span></span><br><span class="line"><span class="string">                transform: translateX(0);</span></span><br><span class="line"><span class="string">                opacity: 1;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">            .card-countdown .item-content:hover .cd-percentage &#123;</span></span><br><span class="line"><span class="string">                transform: translateX(-10px);</span></span><br><span class="line"><span class="string">                opacity: 0;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">        `</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> styleSheet = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;style&quot;</span>);</span><br><span class="line">        styleSheet.<span class="property">textContent</span> = styles;</span><br><span class="line">        <span class="variable language_">document</span>.<span class="property">head</span>.<span class="title function_">appendChild</span>(styleSheet);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> timer;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">start</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="title function_">injectStyles</span>();</span><br><span class="line">        <span class="title function_">updateCountdown</span>();</span><br><span class="line">        timer = <span class="built_in">setInterval</span>(updateCountdown, <span class="number">600000</span>);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    [<span class="string">&#x27;pjax:complete&#x27;</span>, <span class="string">&#x27;DOMContentLoaded&#x27;</span>].<span class="title function_">forEach</span>(<span class="function"><span class="params">event</span> =&gt;</span> <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(event, start));</span><br><span class="line">    <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;pjax:send&#x27;</span>, <span class="function">() =&gt;</span> timer &amp;&amp; <span class="built_in">clearInterval</span>(timer));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> &#123; start, <span class="attr">stop</span>: <span class="function">() =&gt;</span> timer &amp;&amp; <span class="built_in">clearInterval</span>(timer) &#125;;</span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure><p>添加好后记得保存修改的文件。此外还需要在<strong>安知鱼主题的配置文件</strong> <code>inject</code> -&gt; <code>bottom</code> 处进行自定义 js 的引入工作：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="string">&lt;script</span> <span class="string">src=&quot;/js/countdown.js&quot;&gt;&lt;/script&gt;</span></span><br></pre></td></tr></table></figure><h3 id="22-添加-widgetyml-文件"></a> 2.2 添加 widget.yml 文件</h3><p>完成了步骤 2.1 后我们来为小卡片添加 html 倒计时器组件。在博客的 <code>/source/</code> 目录中的 <code>_data</code> 文件夹中创建一个名为 <code>widget.yml</code> 的文件（<code>_data</code> 文件夹是一个数据存储目录，用来存放网站的各种结构化数据。同上，如果你没有 <code>_data</code> 文件夹可以自行创建一个）。目录和文件创建好后，在 <code>widget.yml</code> 文件中添加以下代码：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">top:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">class_name:</span> <span class="string">card-countdown</span></span><br><span class="line">    <span class="attr">id_name:</span></span><br><span class="line">    <span class="attr">name:</span></span><br><span class="line">    <span class="attr">icon:</span></span><br><span class="line">    <span class="attr">html:</span> <span class="string">|</span></span><br><span class="line"><span class="string">      &lt;div class=&quot;cd-count-left&quot;&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;cd-text&quot;&gt;距离&lt;/span&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;cd-name&quot; id=&quot;eventName&quot;&gt;&lt;/span&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;cd-time&quot; id=&quot;daysUntil&quot;&gt;&lt;/span&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;cd-date&quot; id=&quot;eventDate&quot;&gt;&lt;/span&gt;</span></span><br><span class="line"><span class="string">      &lt;/div&gt;</span></span><br><span class="line"><span class="string">      &lt;div id=&quot;countRight&quot; class=&quot;cd-count-right&quot;&gt;&lt;/div&gt;</span></span><br></pre></td></tr></table></figure><h3 id="13-结束语"></a> 1.3 结束语</h3><p>最后 Hexo 三连（<code>hexo cl &amp;&amp; hexo g &amp;&amp; hexo s</code>）就可以在页面侧边栏查看效果了。</p><p>但值得注意的是，步骤 2.1 中的 <code>targetDate: &quot;2026-02-17&quot;,</code> 这部分（第 3 行）js 代码每年需要手动更新一下日期，如果忘记更新的话，年月日倒计时功能不受影响，只是距离春节天数会变为负数。</p><p>最后最后，欢迎大家在评论区给予指正，让我们共同打造快节奏时代不受算法牵制的属于我们自己的小空间！</p>]]></content>
    
    
    <summary type="html">本文提供完整的 Hexo 博客安知鱼主题细节美化教程。包含 _config.yml 字段配置、custom.css 样式编写、Pug 模板修改，以及移动端响应式适配和暗色模式优化，帮助博主美化自己的博客小站。本文是“Hexo博客美化”系列的首篇指南，将持续更新更多实用技巧。</summary>
    
    
    
    <category term="技术文档" scheme="https://blog.yujiay.wang/categories/tech/"/>
    
    <category term="技术实践" scheme="https://blog.yujiay.wang/categories/tech/techPractice/"/>
    
    
    <category term="随笔" scheme="https://blog.yujiay.wang/tags/essays/"/>
    
    <category term="博客" scheme="https://blog.yujiay.wang/tags/blog/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.7 类型转换</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-7_TypeConversion/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-7_TypeConversion/</id>
    <published>2025-11-17T07:40:00.000Z</published>
    <updated>2025-11-27T07:59:10.000Z</updated>
    
    <content type="html"><![CDATA[<p>在 C++ 中，类型转换是将一种数据类型的值转换为另一种数据类型的过程。C++ 提供了多种类型转换方式，主要分为<strong>隐式类型转换</strong>和<strong>显式类型转换</strong>。</p><h2 id="371-隐式类型转换"></a> 3.7.1 隐式类型转换</h2><p><strong>隐式类型转换也称为自动类型转换，是由编译器自动完成的，不需要程序员手动干预。</strong></p><figure class="highlight c++"><figcaption><span>程序代码3-5</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义一个函数，用于打印整数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">printNumber</span><span class="params">(<span class="type">int</span> num)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;传入函数的数字: &quot;</span> &lt;&lt; num &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 算术运算中的类型提升示例</span></span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="type">double</span> b = <span class="number">3.14</span>;</span><br><span class="line">    <span class="comment">// 在加法运算中，int 类型的 a 会自动转换为 double 类型</span></span><br><span class="line">    <span class="type">double</span> result = a + b; </span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;算术运算结果（类型提升）: &quot;</span> &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* ================================================================ */</span></span><br><span class="line">    <span class="comment">// 赋值时的类型转换示例</span></span><br><span class="line">    <span class="type">double</span> num = <span class="number">3.14</span>;</span><br><span class="line">    <span class="comment">// double 类型的 num 会自动转换为 int 类型，小数部分丢失</span></span><br><span class="line">    <span class="type">int</span> integerNum = num; </span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;赋值转换后的整数: &quot;</span> &lt;&lt; integerNum &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* ================================================================ */</span></span><br><span class="line">    <span class="comment">// 函数调用时的类型转换示例</span></span><br><span class="line">    <span class="type">short</span> s = <span class="number">10</span>;</span><br><span class="line">    <span class="comment">// short 类型的 s 会自动转换为 int 类型传递给函数</span></span><br><span class="line">    <span class="built_in">printNumber</span>(s); </span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li>算术运算中的类型提升</li></ol><p>在进行算术运算时，如果操作数的类型不同，编译器会将较低类型提升为较高类型，以确保运算的准确性。类型提升的顺序大致为：<code>char</code>/<code>short</code> -&gt; <code>int</code> -&gt; <code>long</code> -&gt; <code>long long</code> -&gt; <code>float</code> -&gt; <code>double</code>。</p><ol start="2"><li><p>赋值时的类型转换<br />当将一个值赋给不同类型的变量时，编译器会尝试进行隐式类型转换。如果目标类型能够容纳源类型的值，则转换成功；否则可能会导致数据丢失。</p></li><li><p>函数调用时的类型转换<br />在函数调用时，如果实参的类型与形参的类型不匹配，编译器会尝试进行隐式类型转换。</p></li></ol><p>在程序代码3-5中我们清楚的演示了以上三种隐式类型转换的案例，在这个案例中 <code>int</code> 类型的 <code>a</code> 会自动转换为 <code>double</code> 类型。<code>double</code> 类型的 <code>num</code> 会自动转换为 <code>int</code> 类型但会丢失小数部分。<code>short</code> 类型的 <code>s</code> 也会自动转换为 <code>int</code> 类型传递给函数 <code>printNumber</code>。</p><h2 id="372-显式类型转换"></a> 3.7.2 显式类型转换</h2><p>C++ 还允许通过强制类型机制显式的进行类型转换，<strong>显式类型转换也称为强制类型转换，需要程序员手动指定转换的类型。</strong>（C++ 必须有类型规则，而有时候又需要推翻这些死板的规则）。C++ 提供了四种显式类型转换操作符，这将在第15章详细介绍，这里先进行简单说明。</p><ol><li><code>static_cast</code></li></ol><p><code>static_cast</code> 用于基本数据类型之间的转换，以及具有继承关系的类对象指针或引用之间的转换。它在编译时进行类型检查，不进行运行时的类型检查。</p><ol start="2"><li><code>dynamic_cast</code></li></ol><p><code>dynamic_cast</code> 主要用于具有继承关系的类对象指针或引用之间的安全向下转换（将基类指针或引用转换为派生类指针或引用）。它在运行时进行类型检查，如果转换不安全则返回空指针（对于指针转换）或抛出 <code>std::bad_cast</code> 异常（对于引用转换）。</p><ol start="3"><li><p><code>const_cast</code><br /><code>const_cast</code> 用于去除变量的 <code>const</code> 或 <code>volatile</code> 限定符。它只能用于改变对象的常量性或易变性，不能用于改变对象的类型。</p></li><li><p><code>reinterpret_cast</code></p></li></ol><p><code>reinterpret_cast</code> 用于进行最底层的类型转换，它可以将一个指针转换为任意其他类型的指针，也可以将整数类型转换为指针类型。这种转换非常危险，因为它不进行任何类型检查，可能会导致未定义行为。</p><h2 id="373-旧式强制类型转换"></a> 3.7.3 旧式强制类型转换</h2><div class="note info modern"><p><strong>C 风格的强制类型转换</strong></p><p>这是从 C 语言继承过来的强制类型转换方式，其基本格式为：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(type)expression</span><br></pre></td></tr></table></figure><p>其中，type 是目标类型，expression 是需要进行类型转换的表达式。这种转换方式简单直接，但它缺乏类型检查，会在多种不同类型转换场景下使用，可能带来一些潜在风险。</p></div><p>在 C++ 中，还可以使用类似于 C 语言的旧式强制类型转换，语法为 <code>(type)expression</code>。这种转换方式比较简单，但不够安全，因为它会尝试进行各种可能的类型转换，容易导致意外的结果。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">double</span> num = <span class="number">3.14</span>;</span><br><span class="line">    <span class="type">int</span> integerNum = (<span class="type">int</span>)num; <span class="comment">// 旧式强制类型转换</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;Integer number: &quot;</span> &lt;&lt; integerNum &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>综上 C++ 中的类型转换提供了多种方式，你可以根据具体的需求选择合适的类型转换方法。在进行类型转换时，要注意避免数据丢失和未定义行为，尽量使用安全的类型转换操作符。</p>]]></content>
    
    
    <summary type="html">本文详细解析C++中的隐式转换与显式转换机制，涵盖static_cast、dynamic_cast、const_cast及reinterpret_cast的适用场景与风险，并提供代码示例说明如何安全地进行类型转换以避免数据丢失和未定义行为。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.6 操作符重载(选读)</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-6_OperatorOverload/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-6_OperatorOverload/</id>
    <published>2025-11-16T07:40:00.000Z</published>
    <updated>2025-11-16T07:40:00.000Z</updated>
    
    <content type="html"><![CDATA[<div class="note info modern"><p>章节阅读提示</p><p>在学习 C++ 的过程中，<strong>操作符重载是一个具有一定难度的知识点</strong>，可能对于当前阶段只学习到“C++ 算数操作符”的你来说有点超纲。为了让你能更顺畅地学习 C++，我们给出以下阅读建议。</p><p><strong>现阶段建议</strong><br /><strong>目前先跳过操作符重载这部分内容的学习。因为操作符重载涉及到对类和对象、函数重载等更深入知识的理解，而你当前的知识储备可能还不足以完全掌握它。过早接触可能会让你感到困惑，影响学习的积极性和效果。</strong></p><p><strong>后续学习指引</strong><br />当你完成以下几个关键部分的学习后，就可以返回阅读操作符重载这一小节了：</p><ol><li><strong>类和对象</strong></li><li><strong>函数重载</strong></li><li><strong>构造函数和析构函数</strong></li></ol><p>当你完成上述内容的学习后，你将具备足够的知识基础来深入学习操作符重载。此时再返回阅读操作符重载这部分内容，你会发现理解起来更加轻松，也能更好地掌握这一重要的 C++ 特性。</p><p>祝坚持到现在的你，在 C++ 的学习之旅中取得进步！</p><p style="text-align: right;">—— Evilrabbit</p></div><p>在 C++ 中，操作符重载允许我们为自定义类型（如类和结构体）重新定义操作符的行为。结合前面提到的除法（整数除法和浮点数除法），我们可以通过操作符重载让自定义类型也支持除法运算。操作符重载是 C++ 的一项特性，它允许程序员为自定义类型重新定义操作符的行为。通过操作符重载，我们可以让自定义类型像内置类型一样使用各种操作符，增强代码的可读性和可维护性。对于除法操作符 <code>/</code>，我们可以为自定义类型定义其除法行为。</p><h2 id="361-整数除法重载示例"></a> 3.6.1 整数除法重载示例</h2><p>假设我们有一个自定义的 <code>Fraction</code> 类表示分数，我们可以重载除法操作符来实现分数之间的除法。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Fractionz</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> numerator, denominator;;   <span class="comment">// 定义分子和分母</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">// 构造函数</span></span><br><span class="line">    <span class="built_in">Fraction</span>(<span class="type">int</span> num = <span class="number">0</span>, <span class="type">int</span> den = <span class="number">1</span>) : <span class="built_in">numerator</span>(num), <span class="built_in">denominator</span>(den)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (den == <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(<span class="string">&quot;Denominator cannot be zero!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 重载除法操作符</span></span><br><span class="line">    Fraction <span class="keyword">operator</span>/(<span class="type">const</span> Fraction&amp; other) <span class="type">const</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (other.numerator == <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(<span class="string">&quot;Division by zero fraction!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">Fraction</span>(numerator * other.denominator, denominator * other.numerator);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 打印分数</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">print</span><span class="params">()</span> <span class="type">const</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; numerator &lt;&lt; <span class="string">&quot;/&quot;</span> &lt;&lt; denominator &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Fraction <span class="title">f1</span><span class="params">(<span class="number">2</span>, <span class="number">3</span>)</span></span>;</span><br><span class="line">    <span class="function">Fraction <span class="title">f2</span><span class="params">(<span class="number">4</span>, <span class="number">5</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">    &#123;</span><br><span class="line">        Fraction result = f1 / f2;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Result of division: &quot;</span>;</span><br><span class="line">        result.<span class="built_in">print</span>();</span><br><span class="line">    &#125; <span class="built_in">catch</span> (<span class="type">const</span> std::invalid_argument&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cerr &lt;&lt; <span class="string">&quot;Error: &quot;</span> &lt;&lt; e.<span class="built_in">what</span>() &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在上述代码中：</p><ul><li><code>Fraction</code> 类有两个私有成员变量 <code>numerator</code> 和 <code>denominator</code> 分别表示分子和分母。</li><li>构造函数用于初始化分数对象，并检查分母是否为零。</li><li><code>operator/</code> 函数是对除法操作符的重载，它接受一个 <code>Fraction</code> 类型的参数 <code>other</code>，并返回一个新的 <code>Fraction</code> 对象，表示两个分数相除的结果。在进行除法时，也会检查除数的分子是否为零。</li><li><code>print</code> 函数用于打印分数的信息。</li></ul><h2 id="362-浮点数除法重载示例"></a> 3.6.2 浮点数除法重载示例</h2><p>假设我们有一个自定义的 <code>Complex</code> 类表示复数，我们可以重载除法操作符来实现复数之间的除法。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Complex</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">double</span> real;</span><br><span class="line">    <span class="type">double</span> imag;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">// 构造函数</span></span><br><span class="line">    <span class="built_in">Complex</span>(<span class="type">double</span> r = <span class="number">0.0</span>, <span class="type">double</span> i = <span class="number">0.0</span>) : <span class="built_in">real</span>(r), <span class="built_in">imag</span>(i) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 重载除法操作符</span></span><br><span class="line">    Complex <span class="keyword">operator</span>/(<span class="type">const</span> Complex&amp; other) <span class="type">const</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">double</span> denominator = other.real * other.real + other.imag * other.imag;</span><br><span class="line">        <span class="keyword">if</span> (denominator == <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> std::<span class="built_in">invalid_argument</span>(<span class="string">&quot;Division by zero complex number!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">double</span> newReal = (real * other.real + imag * other.imag) / denominator;</span><br><span class="line">        <span class="type">double</span> newImag = (imag * other.real - real * other.imag) / denominator;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">Complex</span>(newReal, newImag);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 打印复数</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">print</span><span class="params">()</span> <span class="type">const</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; real;</span><br><span class="line">        <span class="keyword">if</span> (imag &gt;= <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            std::cout &lt;&lt; <span class="string">&quot; + &quot;</span> &lt;&lt; imag &lt;&lt; <span class="string">&quot;i&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            std::cout &lt;&lt; <span class="string">&quot; - &quot;</span> &lt;&lt; -imag &lt;&lt; <span class="string">&quot;i&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Complex <span class="title">c1</span><span class="params">(<span class="number">2.0</span>, <span class="number">3.0</span>)</span></span>;</span><br><span class="line">    <span class="function">Complex <span class="title">c2</span><span class="params">(<span class="number">4.0</span>, <span class="number">5.0</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">    &#123;</span><br><span class="line">        Complex result = c1 / c2;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Result of division: &quot;</span>;</span><br><span class="line">        result.<span class="built_in">print</span>();</span><br><span class="line">    &#125; <span class="built_in">catch</span> (<span class="type">const</span> std::invalid_argument&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cerr &lt;&lt; <span class="string">&quot;Error: &quot;</span> &lt;&lt; e.<span class="built_in">what</span>() &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在上述代码中：</p><ul><li><code>Complex</code> 类有两个私有成员变量 <code>real</code> 和 <code>imag</code> 分别表示实部和虚部。</li><li>构造函数用于初始化复数对象。</li><li><code>operator/</code> 函数是对除法操作符的重载，它接受一个 <code>Complex</code> 类型的参数 <code>other</code>，并返回一个新的 <code>Complex</code> 对象，表示两个复数相除的结果。在进行除法时，会计算分母并检查是否为零。</li><li><code>print</code> 函数用于打印复数的信息。</li></ul><div class="note warning modern"><ul><li><strong>操作符重载不能改变操作符的优先级和结合性</strong>：操作符重载只是为自定义类型重新定义了操作符的行为，但不会改变操作符原有的优先级和结合性。</li><li><strong>避免滥用操作符重载</strong>：操作符重载应该遵循操作符的常规语义，避免让操作符的行为变得难以理解。</li><li><strong>处理特殊情况</strong>：在重载除法操作符时，一定要处理除数为零的情况，避免出现未定义行为。</li></ul></div><p>通过操作符重载，我们可以让自定义类型像内置类型一样方便地进行除法运算，提高代码的可读性和可维护性。</p>]]></content>
    
    
    <summary type="html">本文详细讲解C++操作符重载的概念和应用，重点展示如何为自定义类型重载除法操作符。通过Fraction类和Complex类的完整代码示例，演示整数除法和浮点数除法的实现方法，包含异常处理和最佳实践指南。适合有一定C++基础的开发者学习操作符重载技术。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.5 C++ 算术操作符</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-5_ArithmeticOperators/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-5_ArithmeticOperators/</id>
    <published>2025-11-16T07:02:00.000Z</published>
    <updated>2025-11-16T07:02:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>大家可能还对学校里作的算术练习记忆犹新，在计算机上也能够体验同样的乐趣。C++ 使用操作符来运算。它提供了几种操作符来完成基本的算术计算;加法、减法、乘法、除法以及求模。每种操作符都使用两个值(操作数)来计算结果，操作符及其操作数构成了表达式。例如，在下面的语句中:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> add = <span class="number">4</span> + <span class="number">2</span>;</span><br></pre></td></tr></table></figure><p>4 和 2 都是操作数，+ 是加法操作符， 4 + 2 则是一个表达式，其值为 6。下面是 C++ 的 5 种基本算术操作符:</p><ul><li>+ 操作符对操作数执行加法运算。例如，4 + 20 等于 24。</li><li>- 操作符从第一个数中减去第二个数。例如，12 - 3 等于 9。</li><li>* 操作符将操作数相乘。例如，28 * 4 等于 112。</li><li>/ 操作符用第一个数除以第二个数。例如，1000 / 5 等于 200。如果两个操作数都是整数，则结果为商的整数部分。例如，17 / 3 等于 5，小数部分被丢弃。</li><li>% 操作符求模。也就是说，它生成第一个数除以第二个数后的余数。例如，19 % 6 为 1，因为 19 是 6 的 3 倍余 1。两个操作数必须都是整型，将该操作符用于浮点数将导致编译错误。如果其中一个是负数，则结果的符号依赖于实现<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>。</li></ul><p>当然，变量和常量都可以用作操作数，由于 % 的操作数只能是整数，因此我们将在后面的例子中讨论它。</p><figure class="highlight c++"><figcaption><span>程序代码3-3</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">float</span> operands, operated;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置为固定点表示法（fixed-point notation）浮点数会以固定的小数位数进行输出，不用科学计数法</span></span><br><span class="line"><span class="comment">     * 如果读者的编译器不接受 ios_base::fixed 也可以使用 ios::fixed</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    cout.<span class="built_in">setf</span>(ios_base::fixed, ios_base::floatfield);</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;输入一个数字：&quot;</span>;</span><br><span class="line">    cin &gt;&gt; operands;    <span class="comment">//操作数</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;输入另一个数字：&quot;</span>;</span><br><span class="line">    cin &gt;&gt; operated;    <span class="comment">//被操作数</span></span><br><span class="line"></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;operands  = &quot;</span> &lt;&lt; operands &lt;&lt; <span class="string">&quot;; operated = &quot;</span> &lt;&lt; operated &lt;&lt; endl;  <span class="comment">// 确认输入</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;operands + operated = &quot;</span> &lt;&lt; operands + operated &lt;&lt; endl;            <span class="comment">//加操作</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;operands - operated = &quot;</span> &lt;&lt; operands - operated &lt;&lt; endl;            <span class="comment">//减操作</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;operands * operated = &quot;</span> &lt;&lt; operands * operated &lt;&lt; endl;            <span class="comment">//乘操作</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;operands / operated = &quot;</span> &lt;&lt; operands / operated &lt;&lt; endl;            <span class="comment">//除操作</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序的正确输出应该与下列文本相似，从中可以看出 C++ 能够完成简单的算术运算</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">输入一个数字：71.16</span><br><span class="line">输入另一个数字：15.30</span><br><span class="line">operands  = 71.160004; operated = 15.300000</span><br><span class="line">operands + operated = 86.460007</span><br><span class="line">operands - operated = 55.860004</span><br><span class="line">operands * operated = 1088.748047</span><br><span class="line">operands / operated = 4.650980</span><br></pre></td></tr></table></figure><p>也许有细心的读者发现了问题！71.16 与 15.30 相加减后结果出现了 .460007 与 .860004。这不是运算问题，而是由于 <code>float</code> 类型表示有效位数的能力有限。C++ 只保证 6 位有效位。如果将 86.460007 四舍五入成 6 位，将得到 86.4600，这是保证精度的正确结果。如果需要更高的精度你可以尝试一下 <code>double</code> 和 <code>long double</code> 的结果。</p><h2 id="351-操作符优先级和结核性"></a> 3.5.1 操作符优先级和结核性</h2><h3 id="操作符优先级"></a> 操作符优先级</h3><p>在数学课上，我们学习过，运算符有其基本的优先级，这即为代数优先级（先乘除、后加减，先括号内、后括号外）。同样在 C++ 中我们也有运算符的优先级，很多表达式都包含有多个操作符。但计算机如何理解并优先使用哪个操作符呢？他们将按照下列介绍逐级参与运算。</p><ol><li>作用域解析操作符（::）</li></ol><p>这是优先级最高的操作符，用于指定命名空间、类或全局作用域中的标识符。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">namespace</span> MyNamespace</span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> value = <span class="number">42</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::cout &lt;&lt; MyNamespace::value &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li>后缀操作符（++、-- 等）</li></ol><p>后缀自增和自减操作符会在表达式计算完成后再对变量的值进行改变。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> num = <span class="number">5</span>;</span><br><span class="line">    <span class="type">int</span> result = num++;  <span class="comment">// 先使用 num 的值 5 赋给 result，然后 num 再自增为 6</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; result &lt;&lt; <span class="string">&quot;, num: &quot;</span> &lt;&lt; num &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li>前缀操作符（++、–、!、~ 等）</li></ol><p>前缀自增和自减操作符会先对变量的值进行改变，然后再参与表达式的计算。逻辑非（!）和按位取反（~）操作符也属于这一类。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> num = <span class="number">5</span>;</span><br><span class="line">    <span class="type">int</span> result = ++num;  <span class="comment">// 先将 num 自增为 6，然后再将 6 赋给 result</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; result &lt;&lt; <span class="string">&quot;, num: &quot;</span> &lt;&lt; num &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="4"><li>乘法、除法和取模操作符（*、/、%）</li></ol><p>这些操作符用于执行乘、除和取模运算，它们的优先级相同。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">3</span>;</span><br><span class="line">    <span class="type">int</span> result = a / b * <span class="number">2</span>;  <span class="comment">// 先进行除法运算 10 / 3 = 3，再进行乘法运算 3 * 2 = 6</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="5"><li>加法和减法操作符（+、-）</li></ol><p>用于执行加法和减法运算，优先级低于乘法、除法和取模操作符。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">3</span>;</span><br><span class="line">    <span class="type">int</span> result = a + b * <span class="number">2</span>;  <span class="comment">// 先进行乘法运算 3 * 2 = 6，再进行加法运算 10 + 6 = 16</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="6"><li>关系操作符（&lt;、&lt;=、&gt;、&gt;=）</li></ol><p>用于比较两个值的大小关系，返回布尔值。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">3</span>;</span><br><span class="line">    <span class="type">bool</span> result = a &gt; b;  <span class="comment">// 比较 a 是否大于 b，结果为 true</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="7"><li>相等性操作符（==、!=）</li></ol><p>用于判断两个值是否相等，返回布尔值。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">3</span>;</span><br><span class="line">    <span class="type">bool</span> result = a == b;  <span class="comment">// 判断 a 是否等于 b，结果为 false</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="8"><li>逻辑与操作符（&amp;&amp;）</li></ol><p>用于逻辑与运算，只有当两个操作数都为真时，结果才为真。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">bool</span> a = <span class="literal">true</span>;</span><br><span class="line">    <span class="type">bool</span> b = <span class="literal">false</span>;</span><br><span class="line">    <span class="type">bool</span> result = a &amp;&amp; b;  <span class="comment">// 逻辑与运算，结果为 false</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="9"><li>逻辑或操作符（||）</li></ol><p>用于逻辑或运算，只要两个操作数中有一个为真，结果就为真。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">bool</span> a = <span class="literal">true</span>;</span><br><span class="line">    <span class="type">bool</span> b = <span class="literal">false</span>;</span><br><span class="line">    <span class="type">bool</span> result = a || b;  <span class="comment">// 逻辑或运算，结果为 true</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="10"><li>条件操作符（?:）</li></ol><p>这是 C++ 中<strong>唯一</strong>的三元操作符，用于根据一个条件表达式的结果选择两个值中的一个。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">3</span>;</span><br><span class="line">    <span class="type">int</span> result = (a &gt; b) ? a : b;  <span class="comment">// 如果 a 大于 b，则结果为 a，否则为 b</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;result: &quot;</span> &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="11"><li>赋值操作符（=、+=、-= 等）</li></ol><p>用于将一个值赋给一个变量，优先级较低。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    a += <span class="number">5</span>;  <span class="comment">// 等价于 a = a + 5，将 a 的值更新为 15</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;a: &quot;</span> &lt;&lt; a &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="操作符结合性"></a> 操作符结合性</h3><p>当一个表达式中出现多个具有相同优先级的操作符时，操作符的结合性决定了它们的计算顺序。结合性分为左结合和右结合：</p><ol><li>左结合</li></ol><p>大多数操作符都是左结合的，即从左到右依次计算。例如，加法和减法操作符就是左结合的：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span> - <span class="number">3</span> - <span class="number">2</span>;  <span class="comment">// 先计算 10 - 3 = 7，再计算 7 - 2 = 5</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;a: &quot;</span> &lt;&lt; a &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li>右结合</li></ol><p>少数操作符是右结合的，如赋值操作符和条件操作符。例如，赋值操作符的右结合性使得连续赋值成为可能：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a, b, c;</span><br><span class="line">    a = b = c = <span class="number">10</span>;  <span class="comment">// 先将 10 赋给 c，再将 c 的值赋给 b，最后将 b 的值赋给 a</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;a: &quot;</span> &lt;&lt; a &lt;&lt; <span class="string">&quot;, b: &quot;</span> &lt;&lt; b &lt;&lt; <span class="string">&quot;, c: &quot;</span> &lt;&lt; c &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div class="note info modern"><p><strong>操作符优先级和结合性共同决定了表达式的计算顺序</strong>。在初期学习编写复杂的 C++ 表达式时，若对操作符的优先级和结合性不确定，建议使用圆括号 <code>()</code> 来明确指定计算顺序，这样可以提高代码的可读性和可维护性，避免因操作符优先级和结合性导致的错误。</p></div><p>以下是完整的 C++ 操作符优先级和结合性列表，按照优先级从高到低排列，同一组内的操作符优先级相同。</p><table><thead><tr><th style="text-align:center">优先级</th><th style="text-align:center">操作符</th><th>名称或含义</th><th>使用形式</th><th style="text-align:center">结合方向</th><th>说明</th></tr></thead><tbody><tr><td style="text-align:center">1</td><td style="text-align:center"><code>::</code></td><td>作用域解析符</td><td><code>namespace::name</code> <br> <code>class::name</code> <br> <code>::name</code></td><td style="text-align:center">左到右</td><td>用于指定作用域，可用于访问命名空间、类中的成员，或全局作用域的名称</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center"><code>()</code></td><td>括号（函数调用、类型转换<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>）</td><td><code>func(arg1, arg2)</code> <br> <code>(type)expression</code></td><td style="text-align:center">左到右</td><td>用于函数调用或强制类型转换</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center"><code>[]</code></td><td>数组下标</td><td><code>array[index]</code></td><td style="text-align:center">左到右</td><td>用于访问数组元素</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center"><code>-&gt;</code></td><td>通过指针访问成员</td><td><code>ptr-&gt;member</code></td><td style="text-align:center">左到右</td><td>用于通过指针访问对象的成员</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center"><code>.</code></td><td>通过对象访问成员</td><td><code>obj.member</code></td><td style="text-align:center">左到右</td><td>用于通过对象访问其成员</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center"><code>++</code></td><td>后缀自增</td><td><code>var++</code></td><td style="text-align:center">左到右</td><td>先使用变量的值，再将变量的值加 1</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center"><code>--</code></td><td>后缀自减</td><td><code>var--</code></td><td style="text-align:center">左到右</td><td>先使用变量的值，再将变量的值减 1</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>++</code></td><td>前缀自增</td><td><code>++var</code></td><td style="text-align:center">右到左</td><td>先将变量的值加 1，再使用变量的值</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>--</code></td><td>前缀自减</td><td><code>--var</code></td><td style="text-align:center">右到左</td><td>先将变量的值减 1，再使用变量的值</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>+</code></td><td>一元正号</td><td><code>+var</code></td><td style="text-align:center">右到左</td><td>通常不改变操作数的值，用于表示正数</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>-</code></td><td>一元负号</td><td><code>-var</code></td><td style="text-align:center">右到左</td><td>对操作数取负</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>!</code></td><td>逻辑非</td><td><code>!condition</code></td><td style="text-align:center">右到左</td><td>对布尔表达式取反</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>~</code></td><td>按位取反</td><td><code>~var</code></td><td style="text-align:center">右到左</td><td>对操作数的每一位取反</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>*</code></td><td>解引用</td><td><code>*ptr</code></td><td style="text-align:center">右到左</td><td>用于访问指针所指向的对象</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>&amp;</code></td><td>取地址</td><td><code>&amp;var</code></td><td style="text-align:center">右到左</td><td>获取变量的内存地址</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>sizeof</code></td><td>求字节数</td><td><code>sizeof(type)</code> <br> <code>sizeof expression</code></td><td style="text-align:center">右到左</td><td>计算类型或表达式所占的字节数</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>new</code> <br> <code>new[]</code></td><td>动态内存分配</td><td><code>new type</code> <br> <code>new type[size]</code></td><td style="text-align:center">右到左</td><td>用于在堆上分配内存</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center"><code>delete</code> <br> <code>delete[]</code></td><td>动态内存释放</td><td><code>delete ptr</code> <br> <code>delete[] arr</code></td><td style="text-align:center">右到左</td><td>用于释放堆上分配的内存</td></tr><tr><td style="text-align:center">4</td><td style="text-align:center"><code>.*</code></td><td>成员指针访问（对象）</td><td><code>obj.*ptr_to_member</code></td><td style="text-align:center">左到右</td><td>通过对象访问成员指针所指向的成员</td></tr><tr><td style="text-align:center">4</td><td style="text-align:center"><code>-&gt;*</code></td><td>成员指针访问（指针）</td><td><code>ptr-&gt;*ptr_to_member</code></td><td style="text-align:center">左到右</td><td>通过指针访问成员指针所指向的成员</td></tr><tr><td style="text-align:center">5</td><td style="text-align:center"><code>*</code></td><td>乘法</td><td><code>a * b</code></td><td style="text-align:center">左到右</td><td>计算两个数的乘积</td></tr><tr><td style="text-align:center">5</td><td style="text-align:center"><code>/</code></td><td>除法</td><td><code>a / b</code></td><td style="text-align:center">左到右</td><td>计算两个数的商</td></tr><tr><td style="text-align:center">5</td><td style="text-align:center"><code>%</code></td><td>取模（取余）</td><td><code>a % b</code></td><td style="text-align:center">左到右</td><td>计算两个整数相除的余数</td></tr><tr><td style="text-align:center">6</td><td style="text-align:center"><code>+</code></td><td>加法</td><td><code>a + b</code></td><td style="text-align:center">左到右</td><td>计算两个数的和</td></tr><tr><td style="text-align:center">6</td><td style="text-align:center"><code>-</code></td><td>减法</td><td><code>a - b</code></td><td style="text-align:center">左到右</td><td>计算两个数的差</td></tr><tr><td style="text-align:center">7</td><td style="text-align:center"><code>&lt;&lt;</code></td><td>按位左移</td><td><code>a &lt;&lt; n</code></td><td style="text-align:center">左到右</td><td>将操作数的二进制位向左移动指定的位数</td></tr><tr><td style="text-align:center">7</td><td style="text-align:center"><code>&gt;&gt;</code></td><td>按位右移</td><td><code>a &gt;&gt; n</code></td><td style="text-align:center">左到右</td><td>将操作数的二进制位向右移动指定的位数</td></tr><tr><td style="text-align:center">8</td><td style="text-align:center"><code>&lt;</code></td><td>小于</td><td><code>a &lt; b</code></td><td style="text-align:center">左到右</td><td>比较两个值的大小，判断左边是否小于右边</td></tr><tr><td style="text-align:center">8</td><td style="text-align:center"><code>&lt;=</code></td><td>小于等于</td><td><code>a &lt;= b</code></td><td style="text-align:center">左到右</td><td>比较两个值的大小，判断左边是否小于等于右边</td></tr><tr><td style="text-align:center">8</td><td style="text-align:center"><code>&gt;</code></td><td>大于</td><td><code>a &gt; b</code></td><td style="text-align:center">左到右</td><td>比较两个值的大小，判断左边是否大于右边</td></tr><tr><td style="text-align:center">8</td><td style="text-align:center"><code>&gt;=</code></td><td>大于等于</td><td><code>a &gt;= b</code></td><td style="text-align:center">左到右</td><td>比较两个值的大小，判断左边是否大于等于右边</td></tr><tr><td style="text-align:center">9</td><td style="text-align:center"><code>==</code></td><td>等于</td><td><code>a == b</code></td><td style="text-align:center">左到右</td><td>判断两个值是否相等</td></tr><tr><td style="text-align:center">9</td><td style="text-align:center"><code>!=</code></td><td>不等于</td><td><code>a != b</code></td><td style="text-align:center">左到右</td><td>判断两个值是否不相等</td></tr><tr><td style="text-align:center">10</td><td style="text-align:center"><code>&amp;</code></td><td>按位与</td><td><code>a &amp; b</code></td><td style="text-align:center">左到右</td><td>对两个操作数的对应二进制位进行与运算</td></tr><tr><td style="text-align:center">11</td><td style="text-align:center"><code>^</code></td><td>按位异或</td><td><code>a ^ b</code></td><td style="text-align:center">左到右</td><td>对两个操作数的对应二进制位进行异或运算</td></tr><tr><td style="text-align:center">12</td><td style="text-align:center"><code>|</code></td><td>按位或</td><td><code>a | b</code></td><td style="text-align:center">左到右</td><td>对两个操作数的对应二进制位进行或运算</td></tr><tr><td style="text-align:center">13</td><td style="text-align:center"><code>&amp;&amp;</code></td><td>逻辑与</td><td><code>a &amp;&amp; b</code></td><td style="text-align:center">左到右</td><td>对两个布尔表达式进行逻辑与运算，有短路特性</td></tr><tr><td style="text-align:center">14</td><td style="text-align:center"><code>||</code></td><td>逻辑或</td><td><code>a || b</code></td><td style="text-align:center">左到右</td><td>对两个布尔表达式进行逻辑或运算，有短路特性</td></tr><tr><td style="text-align:center">15</td><td style="text-align:center"><code>?:</code></td><td>条件运算符</td><td><code>condition ? expr1 : expr2</code></td><td style="text-align:center">右到左</td><td>根据条件表达式的值选择两个表达式之一进行计算</td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>=</code></td><td>赋值</td><td><code>a = b</code></td><td style="text-align:center">右到左</td><td>将右边的值赋给左边的变量</td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>+=</code></td><td>加赋值</td><td><code>a += b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a + b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>-=</code></td><td>减赋值</td><td><code>a -= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a - b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>*=</code></td><td>乘赋值</td><td><code>a *= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a * b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>/=</code></td><td>除赋值</td><td><code>a /= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a / b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>%=</code></td><td>取模赋值</td><td><code>a %= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a % b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>&lt;&lt;=</code></td><td>左移赋值</td><td><code>a &lt;&lt;= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a &lt;&lt; b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>&gt;&gt;=</code></td><td>右移赋值</td><td><code>a &gt;&gt;= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a &gt;&gt; b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>&amp;=</code></td><td>按位与赋值</td><td><code>a &amp;= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a &amp; b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>^=</code></td><td>按位异或赋值</td><td><code>a ^= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a ^ b</code></td></tr><tr><td style="text-align:center">16</td><td style="text-align:center"><code>|=</code></td><td>按位或赋值</td><td><code>a |= b</code></td><td style="text-align:center">右到左</td><td>等价于 <code>a = a | b</code></td></tr><tr><td style="text-align:center">17</td><td style="text-align:center"><code>,</code></td><td>逗号运算符</td><td><code>expr1, expr2</code></td><td style="text-align:center">左到右</td><td>从左到右依次计算表达式，返回最后一个表达式的值</td></tr></tbody></table><p><strong>解释说明</strong></p><ul><li><strong>优先级</strong>：数值越小，优先级越高。高优先级的操作符会先于低优先级的操作符进行计算。</li><li><strong>结合性</strong>：<ul><li><strong>左结合</strong>：表达式中相同优先级的操作符从左到右依次计算。</li><li><strong>右结合</strong>：表达式中相同优先级的操作符从右到左依次计算。</li></ul></li></ul><div class="note warning modern"><p>再次特别提醒</p><ul><li><strong>在编写复杂表达式时，为了提高代码的可读性和避免错误，建议使用括号来明确指定操作符的计算顺序</strong>。</li><li>逻辑与 <code>&amp;&amp;</code> 和逻辑或 <code>||</code> 具有短路特性。对于 <code>&amp;&amp;</code>，如果第一个表达式为假，则不会计算第二个表达式；对于 <code>||</code>，如果第一个表达式为真，则不会计算第二个表达式。</li></ul></div><h2 id="352-除法分支"></a> 3.5.2 除法分支</h2><p>在 C++ 里，算术操作符中的除法操作会根据操作数的数据类型呈现出不同的行为，本小节为你详细介绍整数除法和浮点数除法这两个主要分支：</p><ol><li>整数除法</li></ol><p>当除法操作的两个操作数都是整数类型（像 <code>int</code>、<code>long</code>、<code>short</code> 等）时，C++ 执行的是整数除法。整数除法会直接舍弃商的小数部分，只保留整数部分。</p><ol start="2"><li>浮点数除法</li></ol><p>要是除法操作的操作数中有一个或两个是浮点数类型（例如 <code>float</code>、<code>double</code>），C++ 就会执行浮点数除法，其结果会包含小数部分。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">double</span> a = <span class="number">7.0</span>;</span><br><span class="line">    <span class="type">double</span> b = <span class="number">2.0</span>;</span><br><span class="line">    <span class="type">double</span> result = a / b;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;浮点数除法结果: &quot;</span> &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在这个例子中，<code>a</code> 和 <code>b</code> 都是 <code>double</code> 类型。<code>a / b</code> 执行的是浮点数除法，7.0 除以 2.0 的结果是 3.5，因此最终 result 的值为 <code>3.5</code>。</p><ol start="3"><li>混合类型除法</li></ol><p>当一个操作数是整数类型，另一个是浮点数类型时，整数会被隐式转换为浮点数，然后执行浮点数除法。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">7</span>;</span><br><span class="line">    <span class="type">double</span> b = <span class="number">2.0</span>;</span><br><span class="line">    <span class="type">double</span> result = a / b;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;混合类型除法结果: &quot;</span> &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在这个例子中，<code>a</code> 是 <code>int</code> 类型，<code>b</code> 是 <code>double</code> 类型。在进行除法运算时，<code>a</code> 会被隐式转换为 <code>double</code> 类型，接着执行浮点数除法，所以结果 <code>result</code> 是 <code>3.5</code>。</p><ol start="4"><li>特殊情况：除数为零</li></ol><p>在 C++ 中，无论是整数除法还是浮点数除法，除数都不能为零。如果除数为零，程序会出现未定义行为。对于整数除法，运行时可能会导致程序崩溃；对于浮点数除法，可能会得到 $NaN$（非数）或者 $\pm Inf$（正负无穷大）。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">7</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">// 以下代码会导致未定义行为，不要这样做</span></span><br><span class="line">    <span class="comment">// int result = a / b;</span></span><br><span class="line">    <span class="comment">// std::cout &lt;&lt; result &lt;&lt; std::endl;</span></span><br><span class="line"></span><br><span class="line">    <span class="type">double</span> c = <span class="number">7.0</span>;</span><br><span class="line">    <span class="type">double</span> d = <span class="number">0.0</span>;</span><br><span class="line">    <span class="type">double</span> result2 = c / d;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;浮点数除以零结果: &quot;</span> &lt;&lt; result2 &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在这个例子中，整数除法 <code>a / b</code> 由于除数为零会引发未定义行为，不建议这样使用。而浮点数除法 <code>c / d</code> 中，<code>7.0</code> 除以 <code>0.0</code> 会得到 <code>inf</code>（正无穷大），输出结果可能会因编译器和系统的不同而有所差异。在实际编程中，要确保除数不为零，避免出现未定义行为。</p><h2 id="353-求模操作符"></a> 3.5.3 求模操作符</h2><p>比起求模操作符来说，多数人更熟悉加、减、乘、除，因此这里花些时间介绍这种操作符。</p><div class="note warning modern"><p>首先请特别注意</p><p><strong>除数不能为零</strong>：这是数学上的未定义操作。在任何语言中，试图进行 <code>a % 0</code> 都会导致运行时错误。</p></div><p><strong>求模操作符 <code>%</code> 用于返回整数除法的余数</strong>。在 C++ 里，当两个整数进行除法运算时，使用 <code>/</code> 操作符会得到商的整数部分（即整数除法），而使用 <code>%</code> 操作符则会得到除法运算后的余数。求模操作符与整数除法相结合，特别适合解决把一个量拆分成不同整数单元的问题。下面以常见的单位转换为例进行说明：</p><p>在长度单位体系中，常见的有米、分米、厘米、毫米，其中 1 米 = 10 分米，1 分米 = 10 厘米，1 厘米 = 10 毫米。我们可以将厘米为单位的长度值转换为米和厘米。</p><figure class="highlight c++"><figcaption><span>程序代码3-4</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 定义总厘米长度</span></span><br><span class="line">    <span class="type">int</span> totalCentimeters = <span class="number">235</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用整数除法计算米数</span></span><br><span class="line">    <span class="type">int</span> meters = totalCentimeters / <span class="number">100</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用求模操作符计算剩余的厘米数</span></span><br><span class="line">    <span class="type">int</span> remainingCentimeters = totalCentimeters % <span class="number">100</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 输出转换结果</span></span><br><span class="line">    cout &lt;&lt; totalCentimeters &lt;&lt; <span class="string">&quot; 厘米等于 &quot;</span> &lt;&lt; meters &lt;&lt; <span class="string">&quot; 米 &quot;</span> &lt;&lt; remainingCentimeters &lt;&lt; <span class="string">&quot; 厘米&quot;</span> &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="354-理论巩固和实践建议"></a> 3.5.4 理论巩固和实践建议</h2><p>本小结涉及知识点较多且较为相似，为确保自己不会混淆你应该多次重复文中的运算示例，观察其结果和精度问题。当然你也可以简单尝试一下明知是错误的情况，看看编译器会给出什么样子的报错内容，在这种可控环境下的试错可能对你今后的学习有一定的益处。</p><p>你也可以对以下代码进行补全和尝试获得运算结果：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. 基本算术运算练习</span></span><br><span class="line"><span class="type">int</span> a = <span class="number">15</span>, b = <span class="number">4</span>;</span><br><span class="line"><span class="comment">// 计算并输出：a+b, a-b, a*b, a/b, a%b</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 优先级验证</span></span><br><span class="line"><span class="type">int</span> result1 = <span class="number">3</span> + <span class="number">4</span> * <span class="number">5</span>;     <span class="comment">// 验证乘法优先级高于加法</span></span><br><span class="line"><span class="type">int</span> result2 = (<span class="number">3</span> + <span class="number">4</span>) * <span class="number">5</span>;  <span class="comment">// 验证括号改变优先级</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3. 混合类型运算</span></span><br><span class="line"><span class="type">int</span> x = <span class="number">7</span>;</span><br><span class="line"><span class="type">double</span> y = <span class="number">2.5</span>;</span><br><span class="line"><span class="comment">// 尝试各种组合，观察类型转换规则</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 4. 求模应用扩展</span></span><br><span class="line"><span class="comment">// 将秒数转换为小时、分钟、秒格式</span></span><br><span class="line"><span class="type">int</span> totalSeconds = <span class="number">3665</span>;</span><br><span class="line"><span class="comment">// 使用除法和求模进行转换</span></span><br></pre></td></tr></table></figure><p>建议读者先完成基础练习，确保掌握核心概念后再进行进阶挑战。实践中遇到问题时，可以回看文中的示例代码和解释说明。如确有不理解的地方可以在下方评论区留言，我会一一回复。</p><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>当操作数中出现负数时，余数的符号在不同编程语言中有不同的规定，因此早期的 C++ 标准等将其留给编译器实现来决定。而现代 C++(11 后) 则采取<strong>结果的符号与被除数（第一个数）相同</strong>的方式。例如：-10 % 3的结果是 -1，而 10 % -3的结果是 1。 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>类型转换的具体讲解参见 3.7 类型转换小节。 <a href="#fnref2" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">C++算术运算符完整指南：从基本加减乘除到优先级规则、除法类型差异和求模运算。本文通过实际代码示例详细讲解操作符使用技巧，帮助C++初学者建立扎实的算术运算基础，包含常见错误避免和最佳实践建议。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.4 读取包含文件</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-4_ReadingIncludeFiles/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-4_ReadingIncludeFiles/</id>
    <published>2025-11-15T08:11:00.000Z</published>
    <updated>2025-11-15T08:11:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="341-包含编译指令的-魔咒力量"></a> 3.4.1 包含编译指令的 “魔咒力量”</h2><p>在 C++ 源文件开头，常常会使用 <code>#include</code> 编译指令来包含头文件，例如 <code>#include &lt;iostream&gt;</code> 。对于新手程序员来说，这些包含指令就像是有一种 “魔咒的力量”，因为他们需要通过不断地阅读代码示例、实际编写程序来逐渐了解每个头文件能为程序添加哪些功能。只有正确地包含了所需的头文件，程序才能顺利编译和运行。比如，若要正常使用标准输入输出功能，就需要包含 iostream 头文件。</p><h2 id="342-不要把包含文件当作神秘知识"></a> 3.4.2 不要把包含文件当作神秘知识</h2><p><strong>包含文件本质上就是文本文件，它们包含了函数声明、类定义、宏定义等信息</strong>。新手程序员不应该把这些头文件看作是神秘难懂、只能依赖使用的东西，而应该有勇气去打开并阅读它们。通过直接阅读头文件的内容，可以更深入地了解其中所提供的功能和接口。例如，当你打开 vector 头文件时，就能看到 <code>std::vector</code> 类的定义以及它所提供的各种成员函数。</p><h2 id="343-找到并查看包含文件的内容"></a> 3.4.3 找到并查看包含文件的内容</h2><p>程序中使用 <code>#include</code> 指令包含的所有文件，实际上都存在于计算机的某个位置，或者计算机能够访问到的地方。新手程序员应该学会去找到这些要使用的包含文件，查看它们具体包含了哪些内容。这样做可以让你快速认识到，源文件和头文件是获取知识和信息的优质来源。在很多情况下，它们就是最好的文档。因为头文件中通常会有详细的注释，解释每个函数、类的用途和使用方法。</p><h2 id="344-阅读包含文件习惯的好处"></a> 3.4.4 阅读包含文件习惯的好处</h2><p>当你开始使用更复杂的包含文件，并且在应用程序中引入其他非标准库时，养成阅读包含文件内容的习惯会非常有帮助。非标准库的文档可能不如标准库那么完善和普及，此时直接阅读头文件就成为了了解库功能和使用方法的重要途径。通过阅读头文件，你可以清楚地知道库提供了哪些功能、每个功能如何使用，从而更高效地在自己的程序中使用这些库。</p><p><strong>我们鼓励大家在学习 C++ 的过程中主动去探索和阅读包含文件，将其作为学习和了解 C++ 编程知识的重要资源。</strong></p>]]></content>
    
    
    <summary type="html">了解C++中#include指令的实用价值与学习方法。本文解析头文件包含机制，指导新手如何查看、阅读头文件内容，并养成主动探索的习惯，提升C++编程理解力。适合初学者消除对头文件的神秘感，高效利用代码资源。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>别被短视频吞噬你积极的人生</title>
    <link href="https://blog.yujiay.wang/lifeSharing/ShortVideosDevour/"/>
    <id>https://blog.yujiay.wang/lifeSharing/ShortVideosDevour/</id>
    <published>2025-11-14T08:35:40.000Z</published>
    <updated>2025-11-14T08:35:40.000Z</updated>
    
    <content type="html"><![CDATA[<p>你有没有发现，每次当你想做一件非常正常且对自己提升很有必要的事的时候，你的做事逻辑是：<code>想法出现 -&gt; 拿起手机 -&gt; 打开了短视频 -&gt; 忘记了要干什么 -&gt; 结束了自我提升的机会</code>。我和身边几位朋友都聊过这个话题，我身边朋友清一色都是“我靠一模一样”、“我以为只有我是这样”、“这不很正常吗”以及“现在大家都这样”！</p><p>那么为什么会这样？我们究竟被什么洗脑了？我们还能回到从前吗？</p><p>在这个信息爆炸的时代，我们仿佛陷入了一个怪圈：越是积极向上的人，越容易在短视频的漩涡中无法自拔。每当我们下定决心专注工作和学习，手指却不听使唤地滑向那一个个充满诱惑的图标。互联网心理学（大家常说的网络心理学）家表明：这不是对象个人的意志力问题，这是一场被我们精心设计过的“注意力抢夺”。</p><p>像上文所说的一样，这绝非是你简单的意志力薄弱，而是一场精心策划、基于人类认知弱点的“注意力争夺战”。我们普通人面对的，是无数开发、设计工程师、算法专家以及心理学家精心打造的“多巴胺陷阱”，它精准地把握权衡了大脑寻求即时奖励的机制。越是渴望自我提升、对生活抱有积极期待的人，往往越容易陷入这种“想努力却无力”的漩涡——因为追求“更好”的冲动，恰好被系统巧妙地转化并导流向了那个能提供“即时满足”的虚拟世界。</p><p>因此，当我们自责“为什么就是控制不住”时，或许首先需要认清：这场较量并不公平。我们的对手，是旨在最大化占据用户时间的强大算法和产品逻辑。理解这场“战争”的机制，是我们重获专注力、找回自我主导权的第一步。</p><p>下面我从<strong>社会层面</strong>和<strong>经济层面</strong>简单分析一下当下的情况。</p><h2 id="一-从社会层面来看"></a> 一、从社会层面来看</h2><h3 id="11-社会加速与时间的碎片化"></a> 1.1 社会加速与时间的碎片化</h3><p>现代生活的一个显著特征是“加速”。我们追求更快的工作节奏、更高效的学习方式以及更即时的信息反馈。这种对“速度”的所谓的崇拜，使得我们的时间被切割成无数碎片。短视频“短、平、快”的特性，恰好与这种碎片化的时间结构完美契合。它成为了填充通勤、排队、工作间隙这些“时间缝隙”的首选工具。本应用于休息或短暂放空的片刻，被短视频迅速占据，我们甚至来不及思考是否有更好的方式可以利用这些时间。</p><h3 id="12-社会结构变迁与情感需求的转移"></a> 1.2 社会结构变迁与情感需求的转移</h3><p>社会结构的变化，特别是人际关系的疏离，也为短视频的沉迷提供了土壤。</p><ul><li><strong>现实连接的弱化</strong>：快节奏的生活和高压的工作可能挤压了现实中的深度社交，使得一些人在线上寻求替代性的伪满足。对于独居老人、留守儿童等群体，短视频在某种程度上成为一种填补情感空窗的方式。</li><li><strong>虚拟社群的构建</strong>：短视频平台通过兴趣推荐，快速的帮助用户形成各种亚文化圈层，比如二次元文化圈。这在一定程度上满足了用户的归属感需求。然而，当过度依赖虚拟世界的互动时，可能反而加剧现实生活中的孤独感。</li></ul><h3 id="13-代际差异"></a> 1.3 代际差异</h3><p>尽管青少年短视频沉迷现象备受关注，但需要认识到，短视频沉迷有向全年龄段扩展的趋势。不同年龄段的用户，其沉迷的动因和表现可能有所不同。例如，中老年人可能因社会角色转变、生活空虚而沉迷，青少年可能出于好奇和 peer pressure（同辈压力），而青壮年则可能用于缓解工作压力。单一地针对某一群体进行防治效果有限，需要社会整体的关注和差异化的引导。</p><h3 id="14-自我价值重塑"></a> 1.4 自我价值重塑</h3><p>短视频也深刻地改变了文化传播和消费的形态。它赋予了草根创作者更大的发声平台，促进了传统文化（如京剧、非物质文化遗产）的年轻化传播。但另一方面，文化内容在短视频传播中也可能被简化和娱乐化，一些低俗、炫富的内容可能对价值观，尤其是青少年的价值观，产生潜移默化的不良影响。</p><h2 id="二-从经济层面来看"></a> 二、从经济层面来看</h2><p>现在大部分人提倡的流量就是收益，这句话没有错，我很认可，但如果任何流量都可以转化为收益，那么我只要翻拍刑法的每一条，我一定都可以获得不错的流量和收益。如果人人都这样做、如果短视频中充斥着巨量的原本是用于限制人道德底线的内容，结果会有多可怕？你也不要和我较真说现在监管力度很严格，力度严格也只是“事后买药”。</p><h3 id="21-流量经济的本质与个体"></a> 2.1 流量经济的本质与个体</h3><p>我们身处一个所谓“流量为王”时代，大家注意，是“所谓”！短视频平台凭借其强大的算法推荐和即时反馈机制，成为流量争夺的主战场。在这里，注意力是稀缺资源，直接与经济利益挂钩，形成“<strong>吸睛即吸金</strong>”的短期效应。平台通过精准的算法分析用户的兴趣点，不断推送高刺激性的内容，而内容创作者在流量诱惑下，往往优先选择博眼球的策略，例如制造戏剧冲突、煽动情绪或生产低质快消内容。这种机制表面上赋予用户“选择自由”，实则将人困于信息茧房<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>中。</p><p>系统不断强化你的口味、你的偏好，让你看到的全是“想看的”，而非“要看的”。结果，许多原本积极的人发现自己陷入矛盾：明明想专注工作或者学习时，手指却不自觉滑向短视频入口。这不是单纯的意志力薄弱，而是多巴胺奖赏系统被系统性劫持的表现。神经科学研究表明，短视频的高频切换（平均3-5秒一个画面）会持续激活大脑的奖励中枢，抑制前额叶皮层（负责理性控制），长期下来，人对即时反馈的依赖越来越强，而对深度工作的耐心急剧退化。更严重的是，这种机制催化了人性的懒惰，放大了比较心理，使人在虚拟满足中失去独立思辨能力。</p><p>如果你还没意识到问题的严重性，请看这张表：</p><table><thead><tr><th style="text-align:left">特性</th><th style="text-align:left">作用机制</th><th style="text-align:left">具体表现与后果</th><th style="text-align:left">与物质成瘾的类比</th></tr></thead><tbody><tr><td style="text-align:left"><strong>大脑奖赏系统劫持</strong></td><td style="text-align:left">短视频的快速、新奇刺激持续激活<strong>多巴胺</strong>分泌，构建“行为-即时奖赏”的强链接。</td><td style="text-align:left">大脑适应高水平刺激，对阅读、思考等需要努力才能获得回报的活动兴趣骤减，形成<strong>渴求效应</strong>。</td><td style="text-align:left">与<strong>毒品</strong>类似，直接、强力地激活多巴胺奖赏通路，导致耐受性增强，需要更长时间、更刺激内容来获得同等快感。</td></tr><tr><td style="text-align:left"><strong>认知控制功能抑制</strong></td><td style="text-align:left">高频刺激抑制负责理性控制、决策和专注力的<strong>前额叶皮层</strong>活动。</td><td style="text-align:left"><strong>注意力碎片化</strong>，难以持续专注；<strong>执行力下降</strong>，拖延症加重；<strong>深度思考能力退化</strong>。</td><td style="text-align:left">如冰毒、可卡因等也会导致前额叶功能受损，判断力、控制力下降。</td></tr><tr><td style="text-align:left"><strong>算法与“信息茧房”</strong></td><td style="text-align:left">推荐算法基于用户偏好进行精准、无限的“投喂”，创造高度个性化的舒适区，屏蔽异质信息。</td><td style="text-align:left">思维被固化，认知范围变窄（<strong>信息茧房</strong>）；将平台构建的虚拟环境当作现实，<strong>独立思考能力减弱</strong>。</td><td style="text-align:left">类似于一种“<strong>行为操控</strong>”，通过预测和迎合用户的喜好，使其在不知不觉中接受引导，削弱自主选择能力。</td></tr><tr><td style="text-align:left"><strong>人性的利用与放大</strong></td><td style="text-align:left">设计机制充分利用了人性中对<strong>即时满足</strong>、<strong>懒惰</strong>和<strong>社交认同</strong>的渴望。</td><td style="text-align:left">倾向于不费力地获取快感（懒惰）；在社交媒体的比较中产生焦虑或虚荣（比较心理），需不断从外部获得确认。</td><td style="text-align:left">与<strong>赌博</strong>的机制更相似，利用“<strong>间歇性强化</strong>”原理（不确定的奖励）使人产生强烈依赖，行为难以消退。</td></tr></tbody></table><p>短视频平台基于算法的“个性化推荐”不断强化我们的偏好，将我们困在“信息茧房”中。在我家里时常会出现一种极度影响家庭和谐的情况发生。</p><p>我经常因为一句话或一件事（没有录音没有拍照，甚至没有使用手机）收到与之相关联的商品推荐，关联性非常高，比如前一周我的朋友在小区捡到一只英短猫，因为他家本来就有（猫名）金豆了，无法再容纳一只猫在同一个空间“斗争”了，为了避免这只猫继续流浪或被送到救助站，外加这只猫品种也不错，我就接收了。自此之后我每天收到无数次的猫砂、猫粮、猫草等等等等的商品推荐、直播间推荐。点击不感兴趣都没有什么效果。</p><p>而我父母成天便是“如何在极短时间搞到几个小目标”、“子女教育一定要恨——所谓棍棒出孝子”、炒股推荐等等等等。</p><p>而更年长的一辈爷爷奶奶，每天便是“某某村九旬老人被子女遗弃”、“某某村惊天大案某某弑父弑母”等等等等。</p><p>父母让我少买网上的低价劣质产品，而他们搬回家的快递要比山还高，老辈总幻想没有工作能力的自己会被“抛弃”，每次见面都会说手机上谁谁谁简直不是人，爹娘都会抛弃、挨打，而父母听到就成了另外的画风，“怎么？谁要抛弃你们吗？不会给你们吃喝住吗？”每次看似的不起眼争吵时间久了也会成大问题！</p><p>大数据分析、算法推荐的本质一定是好的，但经过资本家的调教变成了收割人性的敛财工具。中国优秀的美好的传统文化的推流是少的可怜。阶级斗争和财富平均却让他们说的是头头是道。试问？有多少家庭一顿早餐能消费掉2-3万元？在短视频中好像是绝大多数吧？抱歉，写到这里我参杂了太多个人情感以及不满，但我无能无力改变这个现实，我也无法左右大家的意志。我只想说去其糟粕去其精华是我们该干的事情，如果没有精华那就该放下手机去书店逛逛了。</p><h2 id="三-重获专注"></a> 三、重获专注</h2><p>吐槽了太多现在该来说说应对之法了。</p><p>要摆脱短视频的控制，关键在于理解自律的本质。心理学中的“白熊问题<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>”告诉我们：越是压制某个念头，它越会挥之不去。因此，与其强行戒断，不如重新规划我们与短视频的关系。</p><ul><li><p><strong>设立专注时段，我认为重建深度工作能力的关键</strong>。每天安排不受打扰的工作时间，手机打开飞行模式，专注于单一任务。这件事刚开始的时候一定会充满困难，但坚持下来，大脑将重新适应深度思考的状态。其实我坚持写博客也是因为我想戒掉短视频，奈何现在有一部分社交也存在于此，就像没有人能戒掉微信吧。</p></li><li><p><strong>优化视频食谱也很重要</strong>。就像注重饮食健康一样，我们需要精心筛选信息源，取消关注低质内容，主动寻找有价值的信息。将被动接受推荐转为主动搜索获取，带着明确目的使用短视频。</p></li><li><p><strong>最狠的操作方法是其实是实施断舍离</strong>。连续 7 天将短视频使用时间严格控制在最低限度，用优质信息输入和深度工作替代无目的乱刷。同时，打造一个有利于专注的环境，如使用专注类 App、设置飞行模式、明确划分工作与娱乐空间。</p></li><li><p><strong>最重要的是，培养对生活的控制感</strong>。心理学研究发现，拥有高控制感的人往往会感觉自己更年轻、更有活力。当我们能够有效管理自己的时间和注意力时，自然会减少对短视频的依赖。</p></li></ul><p>短视频只是生活的调味品，而非主食。真正积极的人，懂得将宝贵的时间和注意力投入到能够带来持续成长和满足感的活动中。当我们重新掌握注意力的主导权，就能在信息浪潮中保持内心的秩序与工作的效率，成为一个真正的“积极行动者”，而非“积极废人”。</p><h2 id="四-最后"></a> 四、最后</h2><p>信息如此高密度发达的今天请大家永远不忘初心地记住，不论 AI 也好，短视频的推荐算法也罢，它们的产生都是对“人”这个主体对象进行服务的一个特殊实例，我们人类永远是一个具体而又真实的实体，而算法只是服务我们成长的附庸归属，就像汽车永远是载着我们前进的工具，而它不能主导我们想要去往的远方。</p><p>祝大家拥有属于自己的，充实且幸福的每一天！</p><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>&quot;信息茧房&quot;是指人们在信息领域偏执于某爱好从而将自己的了解面局限于、桎梏于像蚕茧一般的“茧房”，对不感兴趣的其它方面形成了无知。 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>后抑制反弹效应（英语：Ironic process theory, ironic rebound, or the white bear problem）,也称为讽刺性反弹或白熊问题, 是指这样一个心理过程：刻意抑制某些想法时，实际上会使这些想法更容易浮出水面。 一个例子是，当某人积极地试图不去想一只白熊时，他实际上更有可能想象一只白熊。—— Wikipedia <a href="#fnref2" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">深刻剖析“想努力却总忍不住刷短视频”的背后真相：一场针对人类大脑奖赏机制而精心设计的“注意力争夺战”。从社会加速、经济驱动到神经科学，带你看清短视频成瘾的底层逻辑，并提供从认知到行动的实用策略，助你重获专注力，夺回生活主导权。</summary>
    
    
    
    <category term="生活分享" scheme="https://blog.yujiay.wang/categories/lifeSharing/"/>
    
    
    <category term="随笔" scheme="https://blog.yujiay.wang/tags/essays/"/>
    
    <category term="生活" scheme="https://blog.yujiay.wang/tags/life/"/>
    
    <category term="算法" scheme="https://blog.yujiay.wang/tags/algorithms/"/>
    
    <category term="科普" scheme="https://blog.yujiay.wang/tags/popularScience/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.3 浮点类型</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-3_FloatingPointTypes/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-3_FloatingPointTypes/</id>
    <published>2025-11-13T09:25:00.000Z</published>
    <updated>2025-11-13T09:25:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>了解了 C++ 的整形后，我们再来看看浮点类型，它们是 C++ 语言第二梯队的基本类型。<strong>所谓浮点类型就是指能够存储带小数部分的数据的数据类型</strong>。这听起来像绕口令，我们举个简单的例子。圆的面积公式是： $S = \pi r^2$，如果 $r = 2.25$ 这里的 $2.25$ 就是一个带有小数部分的数，就需要用浮点类型来存储。</p><p>“浮点型” 这个名称来源于它在计算机内部存储数据的方式。在这种表示方法中，一个浮点数由两部分组成：尾数（也称为有效数字）和指数。尾数是一个固定精度的数字，指数则用于表示小数点的位置，通过改变指数的值，可以让小数点 “浮动”，所以称为 “浮点型”。例如：对于科学计数法表示的数字 $2.34 \times 10^4$，其中 $2.34$ 是尾数，$4$ 是指数。在计算机中存储的浮点数类似这种形式，但计算机采用二进制编码。</p><p>我们之所以要学习使用浮点型，是因为整形无法或者说很难有效地表示一些“超常”的数值范围。例如，我们无法用整形表示太阳到地球的距离（约等于 $1.496 \times 10^{11}$ 米），或是一些极小的数值。且在诸多领域中很多时候我们都需要用到带有小数部分的数值。</p><p>浮点数在计算机中的表示方法与整数有天壤之别，幸运的是我们不必再去过多探究内部实现的细节。我们只需掌握如何使用浮点类型即可。</p><div class="note warning modern"><p>浮点型精度说明</p><p>浮点数的存储方式和有限的位数，可能会导致一些精度问题，比如舍入误差等。在一些连续的计算或者比较运算中，可能会出现意料之外的结果。请务必不要将其用作货币结算或金融相关系统中！应使定点数类型或高精度库。</p></div><h2 id="331-浮点数表示方法"></a> 3.3.1 浮点数表示方法</h2><p>C++ 有两种浮点数表示方式。</p><ol><li>第一种是常用的小数点表示法</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1.0</span><br><span class="line">1.23</span><br><span class="line">12.34</span><br><span class="line">0.0001</span><br><span class="line">27199.10102</span><br></pre></td></tr></table></figure><p>当我们使用浮点类型来保存值时，小数点后即使是 0 小数点也将确保该数字以浮点格式表示即 1.0 而不是 1。</p><ol start="2"><li>第二种是科学计数表示法</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1.23E5</span><br><span class="line">-15.3E9</span><br><span class="line">8.33E5</span><br><span class="line">-8.11e-10</span><br><span class="line">9.54E-8</span><br><span class="line">4.02E+7</span><br></pre></td></tr></table></figure><p>在科学计数法中，“E”（或 “e”）表示<strong>乘以 10 的幂次方</strong>。</p><p>对于 “1.23E5”，其中 “E5” 表示 10 的 5 次方，即 100000，那么就是 $1.23 \times 10^5$ 或 $1.23 \times 100000$ 了。</p><h3 id="332-浮点数的类型"></a> 3.3.2 浮点数的类型</h3><div class="note modern"><p>有效数字是指在一个数中，从该数的第一个非零数字起，直到末尾数字止的数字。这些数字能够真实地反映一个数的精度，用于衡量数据表示的准确性。</p></div><p>在 C++ 中同样也有 <code>float</code>、<code>double</code> 和 <code>long double</code> 三种浮点类型。这些类型数按照它们可以表示的有效数字和允许的指数最小范围来描述的。例如：对于数字 0.0034，它的有效数位是两位（3 和 4），前面的零是用于确定小数点位置的，不是有效数字；而 3.40 这个数字的有效数位是三位（3、4 和最后的 0），最后的 0 表示这个数字精确到了百分位。</p><p>对于浮点型数据，有效数位是衡量其精度的重要指标。如单精度浮点数（float）大约有 6-7 位有效数字，双精度浮点数（double）大约有 15-16 位有效数字。例如:一个 float 类型的数值表示为 3.141592（实际上由于 float 精度限制，这可能已经存在舍入误差），其有效数位约为 6 位；而对于一个 double 类型表示为 3.141592653589793，有效数位约为 15 位。</p><p>事实上，C 和 C++ 对于有效位数的要求是 float 至少 32 位，double 至少 48 位，且不少于 float，而 long double 至少要和 double 一样多。这三种数据类型的有效位数可以一样多，不过通常，float为 32 位，double 为 64 位，long double 为 80、96 或 128 位。而它们的指数范围则至少是 -37～37。</p><div class="note info modern"><ul><li><p>存储位：<br />存储位是指在计算机存储设备（如内存、硬盘等）或数据存储格式中，用于存放数据的最小单元。它主要是从数据存储的物理或逻辑空间角度来考虑的。例如：一个有符号的 8 位整数（存储位为 8 个），可以表示的范围是 -128～127，它通过这些存储位的二进制组合来实现数据的存储。</p></li><li><p>有效数字：<br />有效数字是指在一个数中，从该数的第一个非零数字起，直到末尾数字止的数字。它主要用于表示测量或计算结果的精度。</p></li></ul></div><h2 id="333-浮点常量"></a> 3.3.3 浮点常量</h2><p>在程序中书写浮点常量的时候，程序将把它存储为哪种浮点类型呢？在默认情况下，像 8.24 和 2.4E8 这样的浮点常量都属于 double 类型。如果希望常量为 foat 类型，请使用 <strong>f</strong> 或 <strong>F</strong> 后缀。对于 long double 类型，可使用 <strong>l</strong> 或 <strong>L</strong> 后缀(由于 l 看起来像数字 1，因此 L 是更好的选择)。</p><p>下面是一些范例:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1.234f      // 浮点常量</span><br><span class="line">2.34E20F    // 浮点常量</span><br><span class="line">2.345324E28 // 双精度浮点常量</span><br><span class="line">2.2L        // 长双精度浮点常量</span><br></pre></td></tr></table></figure><h2 id="334-浮点数的优缺点"></a> 3.3.4 浮点数的优缺点</h2><p>浮点数是一种用于表示实数的数值类型，在计算机编程和科学计算中被广泛使用。它有自身独特的优势，但也存在一些缺点。</p><h3 id="优点"></a> 优点</h3><ol><li>能表示大范围的数值</li></ol><p>浮点数可以表示非常大或非常小的数值。例如，在科学计算中，常常会遇到极大或极小的数值，像宇宙中天体的质量（非常大）、微观粒子的尺寸（非常小）等。以常见的双精度浮点数（double）为例，它能表示的数值范围大约是 $\pm1.7\times10^{-300}$ 到 $\pm1.7\times10^{308}$ ，这使得它能够处理各种极端情况下的数值计算。</p><ol start="2"><li>适合近似计算</li></ol><p>在很多实际应用场景中，并不需要精确表示所有数值，只需要一个近似值即可。浮点数可以在一定精度范围内提供对实数的近似表示，满足大多数实际问题的需求。比如在物理模拟、金融计算中的利率计算、图形图像处理中的颜色值表示等领域，使用浮点数进行近似计算可以在保证一定精度的前提下，提高计算效率。</p><ol start="3"><li>支持小数运算</li></ol><p>浮点数能够直接表示和处理小数，这在许多实际应用中是必不可少的。例如，在商业计算中涉及到货币金额的计算，或者在工程领域中对物理量（如长度、重量、速度等）的测量和计算，都需要处理小数部分。使用浮点数可以方便地进行这些小数运算，而无需额外的转换和处理。</p><h3 id="缺点"></a> 缺点</h3><ol><li>存在精度损失</li></ol><p>浮点数在计算机中是以二进制形式存储的，而二进制无法精确表示所有的十进制小数。这就导致在进行浮点数运算时，可能会出现精度损失的问题。例如，对于十进制小数 0.1，它无法用二进制浮点数精确表示，在计算机中存储和计算时会存在一定的误差。这种精度损失在多次运算累积后可能会变得比较明显，影响计算结果的准确性。</p><ol start="2"><li>运算速度相对较慢</li></ol><p>相比于整数运算，浮点数运算通常需要更多的硬件资源和时间。这是因为浮点数的表示和运算规则更为复杂，需要专门的浮点运算单元（FPU）来处理。在一些对性能要求极高的应用场景中，浮点数运算的速度可能会成为瓶颈。例如，在实时游戏开发、高性能计算等领域，大量的浮点数运算可能会导致程序运行缓慢。</p><ol start="3"><li>比较操作存在风险</li></ol><p>由于浮点数存在精度损失，直接使用相等运算符（如 <code>==</code> ）来比较两个浮点数是否相等是不安全的。两个理论上应该相等的浮点数，由于精度误差，在计算机中存储的二进制表示可能会有微小差异，导致比较结果为不相等。在进行浮点数比较时，通常需要设置一个合适的误差范围（例如一个很小的常量），通过判断两个浮点数的差值是否在这个误差范围内来确定它们是否近似相等。</p><div class="note modern"><p>浮点数在表示大范围数值和进行近似计算方面具有优势，但在精度、运算速度和比较操作等方面存在一些缺点。在实际应用中，需要根据具体的需求和场景来选择合适的数据类型。</p></div>]]></content>
    
    
    <summary type="html">入解析C++中的浮点类型（float、double、long double），包括其表示方法、有效位数、精度问题以及适用场景。本文详细介绍了浮点常量的书写规范、优缺点对比，并提供实际代码示例，帮助开发者避免常见的浮点数比较和精度陷阱。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.2 const 常量限定符</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-2_ConstantQualifier/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-2_ConstantQualifier/</id>
    <published>2025-11-13T08:34:00.000Z</published>
    <updated>2025-11-13T08:34:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>在 C++ 中，<code>const</code> 是一个关键字，它的英文全称是 “constant”，中文通常称为 “常量限定符” 或 “常量修饰符”。它用于创建常量（常量是指在程序运行过程中其值不能被改变的量）。const 的主要目的是提高程序的安全性、可靠性和可读性。通过将某些变量声明为 const，可以确保这些变量的值不会被意外修改，从而减少程序中的错误。</p><p>当 const 用于基本数据类型（如 <code>int</code>、<code>double</code>、<code>char</code>等）时，语法形式为 “const 数据类型 变量名 = 值”。例如：<code>const int MAX_LENGTH = 100;</code> 声明了一个 int 型的名为 MAX_LENGTH 的常量，其初始值为 100。在程序的后续部分，任何试图修改 MAX_LENGTH 值的操作都是非法的。例如，下面的代码是错误的：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> <span class="type">int</span> MAX_LENGTH = <span class="number">100</span>;</span><br><span class="line">MAX_LENGTH = <span class="number">200</span>;  <span class="comment">// 编译器会报错，因为不能修改 const 变量的值</span></span><br></pre></td></tr></table></figure><div class="note warning modern"><p>注意：</p><p>如果读者在学习 C++ 之前学习了 C 语言，并打算使用 <code>#define</code> 来定义符号常量，请不要这样做，应该学习 C++ 新的语法使用 <code>const</code>。</p></div><p>我们应该在使用 const 时进行初始化。如果在声明常量时没有赋值，则该常量的值将是不确定的，而且无法修改它。</p>]]></content>
    
    
    <summary type="html">本文是C++ const关键字的终极指南，详细讲解了const在变量、指针、函数参数、返回值及类成员中的用法。通过大量代码示例，帮助您理解如何利用const提高代码的安全性、可读性和性能，并掌握顶层const与底层const的区别。适合所有层次的C++开发者阅读。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》3.1 简单变量</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-1_SimpleVariables/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3-1_SimpleVariables/</id>
    <published>2025-11-12T08:06:00.000Z</published>
    <updated>2025-11-12T08:06:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>当我们编写程序时，通常需要存储一些信息，这些信息有的被临时存储在内存中，有的则长期保存在硬盘等存储设备中。在程序运行期间，变量主要被存储在内存<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>中，本章我们将主要讨论存储在内存中的数据（即变量），的相关内容。把数据存储在计算机中，程序必须明白 3 个必要的特征：</p><ul><li>数据将被存储在哪里</li><li>要以何种类型存储数据</li><li>要存储什么值（内容）</li></ul><p>通过之前的“程序代码”范例，大家应该可以看到我们使用的声明中，类型描述了信息的类型并且通过特殊的字母组合（即单词）描述了其值的<strong>变量名称</strong>。例如程序代码2-2中使用了</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> age;</span><br><span class="line">age = <span class="number">18</span>;</span><br></pre></td></tr></table></figure><p>这些语句告诉程序，他正在存储 <code>int</code> 型整数，并使用 age 来表示 该整数的值（这里是 18 ）。实际上这里没有给出注释，但大家都可以明白 age 代表年龄并且年龄是 18，这便是本文下一小节（3.1.1 变量名）即将提到的一个优秀的变量名的重要性。</p><p>程序会找到一块能够存储 <code>int</code> 型整数的内容，将所占用的内存（存储）单元标记为 age，并将 18 复制到该内存单元中。这些语句执行后，我们任何人不会知道这个值被存储在内存的什么位置，但我们的程序替我们记录了存储的信息。我们可以使用 <code>&amp;</code> 操作符进行检索 age 在内存中的地址。在后续章节，我们会介绍指针的相关操作，届时我们会详细介绍这个操作符。</p><h2 id="311-变量名"></a> 3.1.1 变量名</h2><div class="note modern"><p>我们强烈建议，<span class="highlighter pink">选择命名时要考虑代码的可读性和可维护性，尽量让其他开发者能够通过变量名快速理解其代表的含义。</span></p></div><p>前面我们说到，我们使用的 age 变量名，在没有任何提示的情况下，大多数人都可以明白 age 变量所代表的含义，这就是本小节我们要说的，<strong>C++ 提倡使用有一定含义的变量名</strong>。如果变量表示其他的含义，例如：灯光强度（Light intensity）应将其命名为 lightIntensity 或 light_intensity，尽量避免将其命名为 x 或 gq （光强）等易造成混淆的名称。如果将其命名为 li 在特定的、不会引起混淆的代码环境中，可以使用简洁的缩写，但不太推荐在大型项目中单独使用这种极短的缩写，这非常容易引起歧义。</p><div class="note warning modern"><p>C++ 必须遵守几个简单的命名规则</p><ul><li>在名称中智能使用字母、数字和下划线（_）；</li><li>名称中的第一个字符不能是数字；</li><li>不能将 C++ 中的关键字用于变量名称；</li><li>C++ 严格区分大小写字符；</li><li>C++ 对于变量名称的长度没有限制，名称中所有的字符都有意义；</li><li>以两个下划线和大写字母开头的名称被保留给编译器及其使用的资源所使用，以一个下划线开头的了名称被保留给实现，用于全局标识符（全局标识符是在程序的全局作用域中定义的名称。它可以是全局变量、全局函数、命名空间级别的实体等。）。</li></ul></div><p>“C++ 必须遵守几个简单的命名规则”中最后一点与前几点有所不同。C++ 标准规定，以两个下划线开头且紧跟一个大写字母的名称（例如 <code>__A</code>、<code>__BIG_CONSTANT</code> 等）是保留给编译器及其使用的资源所使用的。这意味着我们不应该在自己的代码中使用这样的名称，否则可能会导致不可预测的结果，因为编译器可能在不同的阶段使用这些特定的名称来实现其内部的功能，或者与特定的平台相关的实现相关联。如果开发者使用了这些保留名称，可能会与编译器的行为产生冲突，导致编译错误、链接错误或者程序在运行时出现奇怪的行为。</p><p>以一个下划线开头的名称（例如 <code>_myVariable</code>、<code>_globalFunction</code> 等）在 C++ 中也有特殊的含义。它们被保留给实现，通常用于全局标识符。这意味着在全局作用域中，我们应该避免使用以单个下划线开头的名称作为自己定义的变量、函数或其他标识符的名称。这样的保留可以确保编译器和链接器在处理程序时不会与开发者定义的名称产生冲突，同时也为实现特定的平台相关功能或编译器内部的实现提供了一定的灵活性。</p><p>总之，如果使用我们将不知道会发生什么，但遵循这些命名规则可以避免与编译器和实现相关的名称冲突，提高程序的可移植性和稳定性。</p><p>下面是一些 C++ 中有效和无效的名称：</p><p>有效的：</p><ul><li>myVariable：由字母开头，后续是字母、数字和下划线的组合，是典型的有效变量名；</li><li>_myVariable1：以单个下划线开头，是有效的，但一般不建议这么用，因为它被保留给实现（虽然通常情况下使用也不会有大问题）；</li><li>myFunction：有效的函数名；</li><li>MyClass：有效的类名；</li><li>inputStream：有明确意义的名称，很常见且有效。</li></ul><p>无效的：</p><ul><li>1myVariable：以数字开头是无效的；</li><li>my Variable：包含空格是无效的；</li><li>my@Variable：包含特殊字符 @ 是无效的；</li><li>int：这是 C++ 的关键字，不能作为标识符名称；</li><li>class：同样是关键字，不能用作名称。</li></ul><p>如果想使用两个及以上单词组成一个名称，通常的做法是用下划线将单词分开，例如：my_variable 或者从第二个单词开始将每个单词的第一个首字母大写（即小驼峰命名法），例如：myVariable。C 和 C++ 开发者更倾向于按照 C 语言的风格使用下划线，而 Java 程序员可能更偏向于使用小驼峰命名法。这两种形式都很容易将单词区分开。</p><div class="note info modern"><p>在 C++ 中，对于类名一般使用大驼峰命名法（即每个单词首字母都大写，如 MyClass）。</p><p>此外，还有一些常见的命名约定，比如：</p><ul><li>常量通常使用全大写字母，单词之间用下划线分隔，例如 MAX_VALUE。</li><li>命名空间通常采用小写字母且可能使用下划线来分隔单词，如 my_namespace。</li></ul><p><strong>总的来说，虽然没有严格的规定，但遵循一定的命名约定可以提高代码的可读性和可维护性。</strong></p></div><h2 id="312-整型"></a> 3.1.2 整型</h2><p>我们都知道，整数有无数个，但如果将无限大的整数也包括进来（尽管它确实属于整数）计算机就不可能用有限的内存来表示所有的整数。因此，我们只能表示所有整数的一个子集。C++ 提供多个整数类型，以便能根据具体要求选择使用最合适的整数类型。</p><p>C++ 基本整数类型分别有以下几种：</p><ol><li><p>char：<br />通常是 1 个字节大小，可以表示字符，也可以作为小范围的整数类型使用。有符号的 char 类型范围通常是 - 128 到 127，无符号的 char 类型范围是 0 到 255。</p></li><li><p>short（短整型）：<br />一般为 2 个字节大小，具体大小和范围取决于编译器和平台。有符号短整型的范围通常在 - 32768 到 32767 之间。</p></li><li><p>int（整型）：<br />通常是 4 个字节大小。有符号整数范围通常在 - 2147483648 到 2147483647 之间。是最常用的整数类型之一。</p></li><li><p>long（长整型）：<br />在不同的平台上大小可能不同，通常至少为 4 个字节。有符号长整型的范围通常比有符号整型更大。</p></li><li><p>long long（长长整型）<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>：<br />C++11 新增的类型，通常为 8 个字节大小，提供更大范围的整数表示。有符号长长整型的范围通常非常大。</p></li></ol><div class="note info modern"><p>位与字节的概念:</p><p>在计算机中，位（bit）和字节（byte）是重要的存储单位概念。</p><p><strong>位（bit）</strong>: 是二进制数据中的最小单位，它的值只有 0 和 1 两种状态。每一位代表一个二进制数字。计算机中的所有数据都是以二进制形式存储和处理的，位用于表示单个的二进制数字，多个位组合在一起可以表示不同的数值、字符或指令。</p><p>例如：</p><ul><li>在一个 8 位的二进制数中，每一位都可以是 0 或 1，通过不同的位组合可以表示 256 种不同的数值。</li></ul><p><strong>字节（byte）</strong>: 是计算机存储容量的基本单位。1 字节等于 8 位。通常用大写的“B”表示字节。字节用于衡量计算机存储容量和数据传输量。在存储方面，一个字符通常占用一个字节的存储空间。例如，在 ASCII 编码中，一个英文字母、数字或标点符号占用 1 个字节。而在 Unicode 编码中，一个字符可能占用多个字节。在数据传输方面，网络带宽通常以字节每秒（B/s）为单位来衡量数据传输的速度。</p><p>例如：</p><ul><li>一个整数类型的数据在计算机中可能占用多个字节的存储空间。比如在 32 位系统中，一个 int 类型通常占用 4 个字节，也就是 32 位。</li><li>一个文件的大小通常以字节为单位来表示。例如，一个 10KB 的文件，实际上是 10 * 1024 = 10240 字节。</li></ul></div><p>每种整型类型都有有符号和无符号版，有符号类型可以表示正数、负数和零。例如，有符号 <code>int</code> 类型通常的取值范围是 -2147483648 到 2147483647。存储时，最高位（最左边的位）被用作符号位，0 表示正数，1 表示负数。无符号类型只能表示非负整数，即零和正数。例如，无符号 <code>int</code> 类型的取值范围通常是 0 到 4294967295。所有的位都用于存储数值，没有符号位。</p><p>有符号类型在发生溢出时，行为通常是未定义的，但在一些情况下可能会以循环的方式处理。例如，有符号 <code>char</code> 类型，如果从最大值继续增加，可能会变为最小值。无符号类型在溢出时，会以循环的方式进行处理。例如，无符号 <code>char</code> 类型从最大值继续增加会变为 0，然后继续增加。有符号类型在进行比较时，会考虑符号。例如，-1 小于 0。无符号类型在比较时只考虑数值大小。如果将一个有符号负数与无符号数比较，有符号数会被隐式转换为无符号数，可能会导致意外的结果。例如，有符号的 -1 转换为无符号数时会变成一个非常大的正数，通常比任何无符号正数都大。</p><p>有符号类型在大多数常规的算术运算和需要考虑正负情况的场景中使用，例如，表示温度的变化、计数的增减等。 无符号类型在确定数值一定是非负的时候使用，例如，表示对象的数量、数组的索引等。而在一些特定的算法中，需要利用无符号类型的循环溢出特性来实现特定的逻辑。</p><div class="note modern"><p>截至 C<ins>23 共有 10 种整型类型使用。但需注意 “10 种整型类型”是一个便于记忆的简化模型，它涵盖了最核心、最常用的整型类别。但 C</ins> 标准实际定义的整型类型体系要更精细和复杂。</p></div><p>可以像使用 int 一样使用这些类型来声明变量：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">short</span> age                       <span class="comment">//有符号短整型</span></span><br><span class="line"><span class="type">int</span> temperature                 <span class="comment">//有符号整型</span></span><br><span class="line"><span class="type">long</span> number_of_rows             <span class="comment">//有符号长整型</span></span><br><span class="line"><span class="type">long</span> <span class="type">long</span> coordinate_values     <span class="comment">//有符号长长整型</span></span><br><span class="line"></span><br><span class="line"><span class="type">unsigned</span> <span class="type">short</span> age                       <span class="comment">//无符号短整型</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> temperature                 <span class="comment">//无符号整型</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> population                 <span class="comment">//无符号长整型</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> <span class="type">long</span> number_of_particles   <span class="comment">//无符号长长整型</span></span><br></pre></td></tr></table></figure><p>当一个数值超过了其对应数据类型的取值范围时，无符号类型变量的值会从 0 重新开始计数。例如，假设 unsigned int 的取值范围是 0 到 4294967295，如果一个无符号整数变量的值为 4294967295，再对其加 1，它会变为 0。当有符号整数类型变量在进行算术运算（如加法、减法等）时发生溢出，结果是未定义行为。在实际运行中，可能出现奇怪的值，或者程序可能出现错误行为甚至崩溃，具体结果取决于编译器和运行环境。例如，对于有符号 8 位整数类型 char，如果其值为 127，再对其进行加 1 操作，结果是不确定的，可能是 -128（在一些编译器中会出现这种结果，因为最高位变为符号位，导致数值变为负数且取了最小值）。</p><div class="note info modern"><p><code>sizeof</code> 运算符</p><p>在 C 和 C++ 中，sizeof 是一个运算符，用于确定给定类型或变量在内存中占用的字节数</p><p>对于数据类型：sizeof(type)，其中 type 可以是任何内置数据类型（如 int、char、double 等）、用户自定义类型（如结构体、类等）或数组类型。 例如，<code>sizeof(int)</code> 返回 int 类型在当前环境下占用的字节数。</p><p>对于变量：sizeof(var)，其中 var 是一个已定义的变量。 例如，<code>int a = 10; sizeof(a)</code> 返回变量 a 所占用的字节数，在这种情况下与 sizeof(int) 的结果相同，因为变量 a 的类型是 int。</p><hr /><p>sizeof 返回的值是无符号整数类型，通常是 <code>size_t</code>。</p><p>对于数组，sizeof 返回整个数组占用的字节数，而不是数组元素的个数。要确定数组元素的个数，可以使用 <code>sizeof(array) / sizeof(array[0])</code>。</p><p>值得注意的是 sizeof 在编译时就会被计算出来，不会导致运行时的性能开销。</p></div><h2 id="313-类型的选择"></a> 3.1.3 类型的选择</h2><p>通过上述学习，我们了解到 C++ 提供了大量的数据类型，应使用哪种类型最为合适呢？</p><p>通常，int 类型被设置为最“自然”的长度。自然长度(natural size)可以理解为该数据类型在当前编译器、操作系统和硬件平台组合下通常被分配的字节数。<strong>它可能是当前编译器、操作系统和硬件平台组合下处理效率最高的长度</strong>。如果没有特定需求或强有力的理由去选择其他类型，则我们建议使用 int。</p><h2 id="314-char-类型"></a> 3.1.4 char 类型</h2><p><code>char</code> 类型，顾名思义，是为了专门存储字符（字符和数字）而设计的。计算机对于存储数字来说算不了什么，但存储字母则情况不同。编程语言通过使用字母的数值编码解决了这个复杂的问题。因此，char 类型可以说是另外一种整形。它足够长，能够表示目标计算机系统中的所有基本符号（数字、字母、符号等）。实际上，大多系统支持的字符都不超过 256 种，因此一个字节就可以表示所有的符号。虽然 char 通常被用来处理字符，但你也可以将它用作比 <code>short</code> 更小的整形。</p><p>通常我们最常用的符号集是美国信息交换标准代码(ASCII, American Standard Code for Information Interchange)字符集。</p><details class="folding-tag" ><summary> ASCII码表 (点击展开) </summary>              <div class='content'>              <table><thead><tr><th style="text-align:center">Bin（二进制）</th><th style="text-align:center">Dec（十进制）</th><th style="text-align:center">Hex（十六进制）</th><th style="text-align:center">缩写/字符</th><th style="text-align:center">解释</th></tr></thead><tbody><tr><td style="text-align:center">0000 0000</td><td style="text-align:center">0</td><td style="text-align:center">0x00</td><td style="text-align:center">NUL(null)</td><td style="text-align:center">空字符</td></tr><tr><td style="text-align:center">0000 0001</td><td style="text-align:center">1</td><td style="text-align:center">0x01</td><td style="text-align:center">SOH(start of headline)</td><td style="text-align:center">标题开始</td></tr><tr><td style="text-align:center">0000 0010</td><td style="text-align:center">2</td><td style="text-align:center">0x02</td><td style="text-align:center">STX (start of text)</td><td style="text-align:center">正文开始</td></tr><tr><td style="text-align:center">0000 0011</td><td style="text-align:center">3</td><td style="text-align:center">0x03</td><td style="text-align:center">ETX (end of text)</td><td style="text-align:center">正文结束</td></tr><tr><td style="text-align:center">0000 0100</td><td style="text-align:center">4</td><td style="text-align:center">0x04</td><td style="text-align:center">EOT (end of transmission)</td><td style="text-align:center">传输结束</td></tr><tr><td style="text-align:center">0000 0101</td><td style="text-align:center">5</td><td style="text-align:center">0x05</td><td style="text-align:center">ENQ (enquiry)</td><td style="text-align:center">请求</td></tr><tr><td style="text-align:center">0000 0110</td><td style="text-align:center">6</td><td style="text-align:center">0x06</td><td style="text-align:center">ACK (acknowledge)</td><td style="text-align:center">收到通知</td></tr><tr><td style="text-align:center">0000 0111</td><td style="text-align:center">7</td><td style="text-align:center">0x07</td><td style="text-align:center">BEL (bell)</td><td style="text-align:center">响铃</td></tr><tr><td style="text-align:center">0000 1000</td><td style="text-align:center">8</td><td style="text-align:center">0x08</td><td style="text-align:center">BS (backspace)</td><td style="text-align:center">退格</td></tr><tr><td style="text-align:center">0000 1001</td><td style="text-align:center">9</td><td style="text-align:center">0x09</td><td style="text-align:center">HT (horizontal tab)</td><td style="text-align:center">水平制表符</td></tr><tr><td style="text-align:center">0000 1010</td><td style="text-align:center">10</td><td style="text-align:center">0x0A</td><td style="text-align:center">LF (NL line feed, new line)</td><td style="text-align:center">换行键</td></tr><tr><td style="text-align:center">0000 1011</td><td style="text-align:center">11</td><td style="text-align:center">0x0B</td><td style="text-align:center">VT (vertical tab)</td><td style="text-align:center">垂直制表符</td></tr><tr><td style="text-align:center">0000 1100</td><td style="text-align:center">12</td><td style="text-align:center">0x0C</td><td style="text-align:center">FF (NP form feed, new page)</td><td style="text-align:center">换页键</td></tr><tr><td style="text-align:center">0000 1101</td><td style="text-align:center">13</td><td style="text-align:center">0x0D</td><td style="text-align:center">CR (carriage return)</td><td style="text-align:center">回车键</td></tr><tr><td style="text-align:center">0000 1110</td><td style="text-align:center">14</td><td style="text-align:center">0x0E</td><td style="text-align:center">SO (shift out)</td><td style="text-align:center">不用切换</td></tr><tr><td style="text-align:center">0000 1111</td><td style="text-align:center">15</td><td style="text-align:center">0x0F</td><td style="text-align:center">SI (shift in)</td><td style="text-align:center">启用切换</td></tr><tr><td style="text-align:center">0001 0000</td><td style="text-align:center">16</td><td style="text-align:center">0x10</td><td style="text-align:center">DLE (data link escape)</td><td style="text-align:center">数据链路转义</td></tr><tr><td style="text-align:center">0001 0001</td><td style="text-align:center">17</td><td style="text-align:center">0x11</td><td style="text-align:center">DC1 (device control 1)</td><td style="text-align:center">设备控制1</td></tr><tr><td style="text-align:center">0001 0010</td><td style="text-align:center">18</td><td style="text-align:center">0x12</td><td style="text-align:center">DC2 (device control 2)</td><td style="text-align:center">设备控制2</td></tr><tr><td style="text-align:center">0001 0011</td><td style="text-align:center">19</td><td style="text-align:center">0x13</td><td style="text-align:center">DC3 (device control 3)</td><td style="text-align:center">设备控制3</td></tr><tr><td style="text-align:center">0001 0100</td><td style="text-align:center">20</td><td style="text-align:center">0x14</td><td style="text-align:center">DC4 (device control 4)</td><td style="text-align:center">设备控制4</td></tr><tr><td style="text-align:center">0001 0101</td><td style="text-align:center">21</td><td style="text-align:center">0x15</td><td style="text-align:center">NAK (negative acknowledge)</td><td style="text-align:center">拒绝接收</td></tr><tr><td style="text-align:center">0001 0110</td><td style="text-align:center">22</td><td style="text-align:center">0x16</td><td style="text-align:center">SYN (synchronous idle)</td><td style="text-align:center">同步空闲</td></tr><tr><td style="text-align:center">0001 0111</td><td style="text-align:center">23</td><td style="text-align:center">0x17</td><td style="text-align:center">ETB (end of trans. block)</td><td style="text-align:center">结束传输块</td></tr><tr><td style="text-align:center">0001 1000</td><td style="text-align:center">24</td><td style="text-align:center">0x18</td><td style="text-align:center">CAN (cancel)</td><td style="text-align:center">取消</td></tr><tr><td style="text-align:center">0001 1001</td><td style="text-align:center">25</td><td style="text-align:center">0x19</td><td style="text-align:center">EM (end of medium)</td><td style="text-align:center">媒介结束</td></tr><tr><td style="text-align:center">0001 1010</td><td style="text-align:center">26</td><td style="text-align:center">0x1A</td><td style="text-align:center">SUB (substitute)</td><td style="text-align:center">代替</td></tr><tr><td style="text-align:center">0001 1011</td><td style="text-align:center">27</td><td style="text-align:center">0x1B</td><td style="text-align:center">ESC (escape)</td><td style="text-align:center">换码(溢出)</td></tr><tr><td style="text-align:center">0001 1100</td><td style="text-align:center">28</td><td style="text-align:center">0x1C</td><td style="text-align:center">FS (file separator)</td><td style="text-align:center">文件分隔符</td></tr><tr><td style="text-align:center">0001 1101</td><td style="text-align:center">29</td><td style="text-align:center">0x1D</td><td style="text-align:center">GS (group separator)</td><td style="text-align:center">分组符</td></tr><tr><td style="text-align:center">0001 1110</td><td style="text-align:center">30</td><td style="text-align:center">0x1E</td><td style="text-align:center">RS (record separator)</td><td style="text-align:center">记录分隔符</td></tr><tr><td style="text-align:center">0001 1111</td><td style="text-align:center">31</td><td style="text-align:center">0x1F</td><td style="text-align:center">US (unit separator)</td><td style="text-align:center">单元分隔符</td></tr><tr><td style="text-align:center">0010 0000</td><td style="text-align:center">32</td><td style="text-align:center">0x20</td><td style="text-align:center">(space)</td><td style="text-align:center">空格</td></tr><tr><td style="text-align:center">0010 0001</td><td style="text-align:center">33</td><td style="text-align:center">0x21</td><td style="text-align:center">!</td><td style="text-align:center">叹号</td></tr><tr><td style="text-align:center">0010 0010</td><td style="text-align:center">34</td><td style="text-align:center">0x22</td><td style="text-align:center">&quot;</td><td style="text-align:center">双引号</td></tr><tr><td style="text-align:center">0010 0011</td><td style="text-align:center">35</td><td style="text-align:center">0x23</td><td style="text-align:center">#</td><td style="text-align:center">井号</td></tr><tr><td style="text-align:center">0010 0100</td><td style="text-align:center">36</td><td style="text-align:center">0x24</td><td style="text-align:center">$</td><td style="text-align:center">美元符</td></tr><tr><td style="text-align:center">0010 0101</td><td style="text-align:center">37</td><td style="text-align:center">0x25</td><td style="text-align:center">%</td><td style="text-align:center">百分号</td></tr><tr><td style="text-align:center">0010 0110</td><td style="text-align:center">38</td><td style="text-align:center">0x26</td><td style="text-align:center">&amp;</td><td style="text-align:center">和号</td></tr><tr><td style="text-align:center">0010 0111</td><td style="text-align:center">39</td><td style="text-align:center">0x27</td><td style="text-align:center">’</td><td style="text-align:center">单引号</td></tr><tr><td style="text-align:center">0010 1000</td><td style="text-align:center">40</td><td style="text-align:center">0x28</td><td style="text-align:center">(</td><td style="text-align:center">开括号</td></tr><tr><td style="text-align:center">0010 1001</td><td style="text-align:center">41</td><td style="text-align:center">0x29</td><td style="text-align:center">)</td><td style="text-align:center">闭括号</td></tr><tr><td style="text-align:center">0010 1010</td><td style="text-align:center">42</td><td style="text-align:center">0x2A</td><td style="text-align:center">*</td><td style="text-align:center">星号</td></tr><tr><td style="text-align:center">0010 1011</td><td style="text-align:center">43</td><td style="text-align:center">0x2B</td><td style="text-align:center">+</td><td style="text-align:center">加号</td></tr><tr><td style="text-align:center">0010 1100</td><td style="text-align:center">44</td><td style="text-align:center">0x2C</td><td style="text-align:center">,</td><td style="text-align:center">逗号</td></tr><tr><td style="text-align:center">0010 1101</td><td style="text-align:center">45</td><td style="text-align:center">0x2D</td><td style="text-align:center">-</td><td style="text-align:center">减号/破折号</td></tr><tr><td style="text-align:center">0010 1110</td><td style="text-align:center">46</td><td style="text-align:center">0x2E</td><td style="text-align:center">.</td><td style="text-align:center">句号</td></tr><tr><td style="text-align:center">0010 1111</td><td style="text-align:center">47</td><td style="text-align:center">0x2F</td><td style="text-align:center">/</td><td style="text-align:center">斜杠</td></tr><tr><td style="text-align:center">0011 0000</td><td style="text-align:center">48</td><td style="text-align:center">0x30</td><td style="text-align:center">0</td><td style="text-align:center">字符0</td></tr><tr><td style="text-align:center">0011 0001</td><td style="text-align:center">49</td><td style="text-align:center">0x31</td><td style="text-align:center">1</td><td style="text-align:center">字符1</td></tr><tr><td style="text-align:center">0011 0010</td><td style="text-align:center">50</td><td style="text-align:center">0x32</td><td style="text-align:center">2</td><td style="text-align:center">字符2</td></tr><tr><td style="text-align:center">0011 0011</td><td style="text-align:center">51</td><td style="text-align:center">0x33</td><td style="text-align:center">3</td><td style="text-align:center">字符3</td></tr><tr><td style="text-align:center">0011 0100</td><td style="text-align:center">52</td><td style="text-align:center">0x34</td><td style="text-align:center">4</td><td style="text-align:center">字符4</td></tr><tr><td style="text-align:center">0011 0101</td><td style="text-align:center">53</td><td style="text-align:center">0x35</td><td style="text-align:center">5</td><td style="text-align:center">字符5</td></tr><tr><td style="text-align:center">0011 0110</td><td style="text-align:center">54</td><td style="text-align:center">0x36</td><td style="text-align:center">6</td><td style="text-align:center">字符6</td></tr><tr><td style="text-align:center">0011 0111</td><td style="text-align:center">55</td><td style="text-align:center">0x37</td><td style="text-align:center">7</td><td style="text-align:center">字符7</td></tr><tr><td style="text-align:center">0011 1000</td><td style="text-align:center">56</td><td style="text-align:center">0x38</td><td style="text-align:center">8</td><td style="text-align:center">字符8</td></tr><tr><td style="text-align:center">0011 1001</td><td style="text-align:center">57</td><td style="text-align:center">0x39</td><td style="text-align:center">9</td><td style="text-align:center">字符9</td></tr><tr><td style="text-align:center">0011 1010</td><td style="text-align:center">58</td><td style="text-align:center">0x3A</td><td style="text-align:center">:</td><td style="text-align:center">冒号</td></tr><tr><td style="text-align:center">0011 1011</td><td style="text-align:center">59</td><td style="text-align:center">0x3B</td><td style="text-align:center">;</td><td style="text-align:center">分号</td></tr><tr><td style="text-align:center">0011 1100</td><td style="text-align:center">60</td><td style="text-align:center">0x3C</td><td style="text-align:center">&lt;</td><td style="text-align:center">小于</td></tr><tr><td style="text-align:center">0011 1101</td><td style="text-align:center">61</td><td style="text-align:center">0x3D</td><td style="text-align:center">=</td><td style="text-align:center">等号</td></tr><tr><td style="text-align:center">0011 1110</td><td style="text-align:center">62</td><td style="text-align:center">0x3E</td><td style="text-align:center">&gt;</td><td style="text-align:center">大于</td></tr><tr><td style="text-align:center">0011 1111</td><td style="text-align:center">63</td><td style="text-align:center">0x3F</td><td style="text-align:center">?</td><td style="text-align:center">问号</td></tr><tr><td style="text-align:center">0100 0000</td><td style="text-align:center">64</td><td style="text-align:center">0x40</td><td style="text-align:center">@</td><td style="text-align:center">电子邮件符号</td></tr><tr><td style="text-align:center">0100 0001</td><td style="text-align:center">65</td><td style="text-align:center">0x41</td><td style="text-align:center">A</td><td style="text-align:center">大写字母 A</td></tr><tr><td style="text-align:center">0100 0010</td><td style="text-align:center">66</td><td style="text-align:center">0x42</td><td style="text-align:center">B</td><td style="text-align:center">大写字母 B</td></tr><tr><td style="text-align:center">0100 0011</td><td style="text-align:center">67</td><td style="text-align:center">0x43</td><td style="text-align:center">C</td><td style="text-align:center">大写字母 C</td></tr><tr><td style="text-align:center">0100 0100</td><td style="text-align:center">68</td><td style="text-align:center">0x44</td><td style="text-align:center">D</td><td style="text-align:center">大写字母 D</td></tr><tr><td style="text-align:center">0100 0101</td><td style="text-align:center">69</td><td style="text-align:center">0x45</td><td style="text-align:center">E</td><td style="text-align:center">大写字母 E</td></tr><tr><td style="text-align:center">0100 0110</td><td style="text-align:center">70</td><td style="text-align:center">0x46</td><td style="text-align:center">F</td><td style="text-align:center">大写字母 F</td></tr><tr><td style="text-align:center">0100 0111</td><td style="text-align:center">71</td><td style="text-align:center">0x47</td><td style="text-align:center">G</td><td style="text-align:center">大写字母 G</td></tr><tr><td style="text-align:center">0100 1000</td><td style="text-align:center">72</td><td style="text-align:center">0x48</td><td style="text-align:center">H</td><td style="text-align:center">大写字母 H</td></tr><tr><td style="text-align:center">0100 1001</td><td style="text-align:center">73</td><td style="text-align:center">0x49</td><td style="text-align:center">I</td><td style="text-align:center">大写字母 I</td></tr><tr><td style="text-align:center">01001010</td><td style="text-align:center">74</td><td style="text-align:center">0x4A</td><td style="text-align:center">J</td><td style="text-align:center">大写字母 J</td></tr><tr><td style="text-align:center">0100 1011</td><td style="text-align:center">75</td><td style="text-align:center">0x4B</td><td style="text-align:center">K</td><td style="text-align:center">大写字母 K</td></tr><tr><td style="text-align:center">0100 1100</td><td style="text-align:center">76</td><td style="text-align:center">0x4C</td><td style="text-align:center">L</td><td style="text-align:center">大写字母 L</td></tr><tr><td style="text-align:center">0100 1101</td><td style="text-align:center">77</td><td style="text-align:center">0x4D</td><td style="text-align:center">M</td><td style="text-align:center">大写字母 M</td></tr><tr><td style="text-align:center">0100 1110</td><td style="text-align:center">78</td><td style="text-align:center">0x4E</td><td style="text-align:center">N</td><td style="text-align:center">大写字母 N</td></tr><tr><td style="text-align:center">0100 1111</td><td style="text-align:center">79</td><td style="text-align:center">0x4F</td><td style="text-align:center">O</td><td style="text-align:center">大写字母 O</td></tr><tr><td style="text-align:center">0101 0000</td><td style="text-align:center">80</td><td style="text-align:center">0x50</td><td style="text-align:center">P</td><td style="text-align:center">大写字母 P</td></tr><tr><td style="text-align:center">0101 0001</td><td style="text-align:center">81</td><td style="text-align:center">0x51</td><td style="text-align:center">Q</td><td style="text-align:center">大写字母 Q</td></tr><tr><td style="text-align:center">0101 0010</td><td style="text-align:center">82</td><td style="text-align:center">0x52</td><td style="text-align:center">R</td><td style="text-align:center">大写字母 R</td></tr><tr><td style="text-align:center">0101 0011</td><td style="text-align:center">83</td><td style="text-align:center">0x53</td><td style="text-align:center">S</td><td style="text-align:center">大写字母 S</td></tr><tr><td style="text-align:center">0101 0100</td><td style="text-align:center">84</td><td style="text-align:center">0x54</td><td style="text-align:center">T</td><td style="text-align:center">大写字母 T</td></tr><tr><td style="text-align:center">0101 0101</td><td style="text-align:center">85</td><td style="text-align:center">0x55</td><td style="text-align:center">U</td><td style="text-align:center">大写字母 U</td></tr><tr><td style="text-align:center">0101 0110</td><td style="text-align:center">86</td><td style="text-align:center">0x56</td><td style="text-align:center">V</td><td style="text-align:center">大写字母 V</td></tr><tr><td style="text-align:center">0101 0111</td><td style="text-align:center">87</td><td style="text-align:center">0x57</td><td style="text-align:center">W</td><td style="text-align:center">大写字母 W</td></tr><tr><td style="text-align:center">0101 1000</td><td style="text-align:center">88</td><td style="text-align:center">0x58</td><td style="text-align:center">X</td><td style="text-align:center">大写字母 X</td></tr><tr><td style="text-align:center">0101 1001</td><td style="text-align:center">89</td><td style="text-align:center">0x59</td><td style="text-align:center">Y</td><td style="text-align:center">大写字母 Y</td></tr><tr><td style="text-align:center">0101 1010</td><td style="text-align:center">90</td><td style="text-align:center">0x5A</td><td style="text-align:center">Z</td><td style="text-align:center">大写字母 Z</td></tr><tr><td style="text-align:center">0101 1011</td><td style="text-align:center">91</td><td style="text-align:center">0x5B</td><td style="text-align:center">[</td><td style="text-align:center">开方括号</td></tr><tr><td style="text-align:center">0101 1100</td><td style="text-align:center">92</td><td style="text-align:center">0x5C</td><td style="text-align:center">\</td><td style="text-align:center">反斜杠</td></tr><tr><td style="text-align:center">0101 1101</td><td style="text-align:center">93</td><td style="text-align:center">0x5D</td><td style="text-align:center">]</td><td style="text-align:center">闭方括号</td></tr><tr><td style="text-align:center">0101 1110</td><td style="text-align:center">94</td><td style="text-align:center">0x5E</td><td style="text-align:center">^</td><td style="text-align:center">脱字符</td></tr><tr><td style="text-align:center">0101 1111</td><td style="text-align:center">95</td><td style="text-align:center">0x5F</td><td style="text-align:center">_</td><td style="text-align:center">下划线</td></tr><tr><td style="text-align:center">0110 0000</td><td style="text-align:center">96</td><td style="text-align:center">0x60</td><td style="text-align:center">`</td><td style="text-align:center">开单引号</td></tr><tr><td style="text-align:center">0110 0001</td><td style="text-align:center">97</td><td style="text-align:center">0x61</td><td style="text-align:center">a</td><td style="text-align:center">小写字母 a</td></tr><tr><td style="text-align:center">0110 0010</td><td style="text-align:center">98</td><td style="text-align:center">0x62</td><td style="text-align:center">b</td><td style="text-align:center">小写字母 b</td></tr><tr><td style="text-align:center">0110 0011</td><td style="text-align:center">99</td><td style="text-align:center">0x63</td><td style="text-align:center">c</td><td style="text-align:center">小写字母 c</td></tr><tr><td style="text-align:center">0110 0100</td><td style="text-align:center">100</td><td style="text-align:center">0x64</td><td style="text-align:center">d</td><td style="text-align:center">小写字母 d</td></tr><tr><td style="text-align:center">0110 0101</td><td style="text-align:center">101</td><td style="text-align:center">0x65</td><td style="text-align:center">e</td><td style="text-align:center">小写字母 e</td></tr><tr><td style="text-align:center">0110 0110</td><td style="text-align:center">102</td><td style="text-align:center">0x66</td><td style="text-align:center">f</td><td style="text-align:center">小写字母 f</td></tr><tr><td style="text-align:center">0110 0111</td><td style="text-align:center">103</td><td style="text-align:center">0x67</td><td style="text-align:center">g</td><td style="text-align:center">小写字母 g</td></tr><tr><td style="text-align:center">0110 1000</td><td style="text-align:center">104</td><td style="text-align:center">0x68</td><td style="text-align:center">h</td><td style="text-align:center">小写字母 h</td></tr><tr><td style="text-align:center">0110 1001</td><td style="text-align:center">105</td><td style="text-align:center">0x69</td><td style="text-align:center">i</td><td style="text-align:center">小写字母 i</td></tr><tr><td style="text-align:center">0110 1010</td><td style="text-align:center">106</td><td style="text-align:center">0x6A</td><td style="text-align:center">j</td><td style="text-align:center">小写字母 j</td></tr><tr><td style="text-align:center">0110 1011</td><td style="text-align:center">107</td><td style="text-align:center">0x6B</td><td style="text-align:center">k</td><td style="text-align:center">小写字母 k</td></tr><tr><td style="text-align:center">0110 1100</td><td style="text-align:center">108</td><td style="text-align:center">0x6C</td><td style="text-align:center">l</td><td style="text-align:center">小写字母 l</td></tr><tr><td style="text-align:center">0110 1101</td><td style="text-align:center">109</td><td style="text-align:center">0x6D</td><td style="text-align:center">m</td><td style="text-align:center">小写字母 m</td></tr><tr><td style="text-align:center">0110 1110</td><td style="text-align:center">110</td><td style="text-align:center">0x6E</td><td style="text-align:center">n</td><td style="text-align:center">小写字母 n</td></tr><tr><td style="text-align:center">0110 1111</td><td style="text-align:center">111</td><td style="text-align:center">0x6F</td><td style="text-align:center">o</td><td style="text-align:center">小写字母 o</td></tr><tr><td style="text-align:center">0111 0000</td><td style="text-align:center">112</td><td style="text-align:center">0x70</td><td style="text-align:center">p</td><td style="text-align:center">小写字母 p</td></tr><tr><td style="text-align:center">0111 0001</td><td style="text-align:center">113</td><td style="text-align:center">0x71</td><td style="text-align:center">q</td><td style="text-align:center">小写字母 q</td></tr><tr><td style="text-align:center">0111 0010</td><td style="text-align:center">114</td><td style="text-align:center">0x72</td><td style="text-align:center">r</td><td style="text-align:center">小写字母 r</td></tr><tr><td style="text-align:center">0111 0011</td><td style="text-align:center">115</td><td style="text-align:center">0x73</td><td style="text-align:center">s</td><td style="text-align:center">小写字母 s</td></tr><tr><td style="text-align:center">0111 0100</td><td style="text-align:center">116</td><td style="text-align:center">0x74</td><td style="text-align:center">t</td><td style="text-align:center">小写字母 t</td></tr><tr><td style="text-align:center">0111 0101</td><td style="text-align:center">117</td><td style="text-align:center">0x75</td><td style="text-align:center">u</td><td style="text-align:center">小写字母 u</td></tr><tr><td style="text-align:center">0111 0110</td><td style="text-align:center">118</td><td style="text-align:center">0x76</td><td style="text-align:center">v</td><td style="text-align:center">小写字母 v</td></tr><tr><td style="text-align:center">0111 0111</td><td style="text-align:center">119</td><td style="text-align:center">0x77</td><td style="text-align:center">w</td><td style="text-align:center">小写字母 w</td></tr><tr><td style="text-align:center">0111 1000</td><td style="text-align:center">120</td><td style="text-align:center">0x78</td><td style="text-align:center">x</td><td style="text-align:center">小写字母 x</td></tr><tr><td style="text-align:center">0111 1001</td><td style="text-align:center">121</td><td style="text-align:center">0x79</td><td style="text-align:center">y</td><td style="text-align:center">小写字母 y</td></tr><tr><td style="text-align:center">0111 1010</td><td style="text-align:center">122</td><td style="text-align:center">0x7A</td><td style="text-align:center">z</td><td style="text-align:center">小写字母 z</td></tr><tr><td style="text-align:center">0111 1011</td><td style="text-align:center">123</td><td style="text-align:center">0x7B</td><td style="text-align:center">{</td><td style="text-align:center">开花括号</td></tr><tr><td style="text-align:center">0111 1100</td><td style="text-align:center">124</td><td style="text-align:center">0x7C</td><td style="text-align:center">|</td><td style="text-align:center">垂线</td></tr><tr><td style="text-align:center">0111 1101</td><td style="text-align:center">125</td><td style="text-align:center">0x7D</td><td style="text-align:center">}</td><td style="text-align:center">闭花括号</td></tr><tr><td style="text-align:center">0111 1110</td><td style="text-align:center">126</td><td style="text-align:center">0x7E</td><td style="text-align:center">~</td><td style="text-align:center">波浪号</td></tr><tr><td style="text-align:center">0111 1111</td><td style="text-align:center">127</td><td style="text-align:center">0x7F</td><td style="text-align:center">DEL (delete)</td><td style="text-align:center">删除</td></tr></tbody></table>              </div>            </details><p>字符集中的字符用 ASCII 表中的十进制数值编码表示。例如字符 A 的编码为 65，字符 a 的编码为 97。为了方便起见，我们只会记忆码表的一部分规律和个别开头字符，例如：</p><ul><li>数字 0 - 9 的 ASCII 码是连续的，可以一起记忆，编码范围是 48（‘0’）到 57（‘9’）；</li><li>大写字母 A - Z 的 ASCII 码也是连续的，范围是 65（‘A’）到 90（‘Z’）；</li><li>小写字母 a - z 的 ASCII 码同样连续，范围是 97（‘a’）到 122（‘z’）。</li></ul><p>不过 ASCII 编码并不能很好的满足国际化需求，C++ 支持的宽字符类型可以存储更多的值。但考虑到大多数读者对于学习难易的接受程度不同，我们只能优先出于简单学习起见，介绍 ASCII 码（也许随着本书的完善，我们会在后续章节对其他编码作出介绍，例如支持中文和其他基本包含所有国际化文字的 Unicode 字符集）。</p><p>但我们会在本文后续小节（3.1.4-4 wchar_t）介绍一种 C++ 支持的宽字符 <code>wchar_t</code> 类型。</p><figure class="highlight c++"><figcaption><span>程序代码3-1</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">char</span> character;                             <span class="comment">//声明 char 类型的 character 变量</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Please enter a character: &quot;</span>;</span><br><span class="line">    cin &gt;&gt; character;                           <span class="comment">//输入一个字符</span></span><br><span class="line">    cout &lt;&lt; character &lt;&lt; endl;                  <span class="comment">//程序输出输入的字符 第一次结果输出</span></span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> decCharacter = character;               <span class="comment">//声明 int 类型的 decCharacter 变量，用于存储字符的十进制值</span></span><br><span class="line">    <span class="type">int</span> newCharacter = decCharacter + <span class="number">1</span>;        <span class="comment">//声明 int 类型的 newCharacter 变量，用于存储输入字符下一个字符的十进制值</span></span><br><span class="line">    <span class="type">char</span> nextCharacter = newCharacter;          <span class="comment">//将新的结果存储(转换)为 char 类型的值</span></span><br><span class="line"></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Input characters: &quot;</span> &lt;&lt; character &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Enter the decimal value of the character: &quot;</span> &lt;&lt; decCharacter &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;The character that is the decimal value of the input character plus one: &quot;</span> &lt;&lt; nextCharacter &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序代码3-1使用了 <code>char</code> 类型，我们输入了某一个字符（这里假定我们输入字符 ‘E’），程序将会输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Please enter a character: E</span><br><span class="line">E</span><br><span class="line">Input characters: E</span><br><span class="line">Enter the decimal value of the character: 69</span><br><span class="line">The character that is the decimal value of the input character plus one: F</span><br></pre></td></tr></table></figure><p>其运行结果很有趣，我们输入了一个字母，程序会输出该字母而不是对应的字符编码。反之同样，当你尝试输入字符编码后程序也会输出字符编码，而不是字母。这种有趣的现象源于 char 类型。而如果通过断点调试后你会发现，输入时 cin 将 E 转为了 69 存储在内存中，输出时又进行了逆操作。<strong>而 cin 和 cout 都是由变量的类型所引导的</strong>。如果将 69 存储在 int 变量中，cout 将会把他显示为 69。</p><p>在 C++ 中，我们将字符用单引号引起来，例如：<code>char character = 'E';</code>，将字符串用双引号引起来，例如：<code>string str = &quot;Echo&quot;;</code>。cout 对象可以处理这两种情况。同时借此我们将会引导大家学习一项 cout 的新特性 —— <code>cout.put()</code> 函数。</p><h3 id="314-1-成员函数-coutput"></a> 3.1.4-1 成员函数<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> cout.put()</h3><p>到底什么是 <code>cout.put()</code> 函数？其中为什么会需要“用一个点来点出”函数？</p><p>成员函数是一个重要的 C++ 面向对象(OOP)概念。它用于操作类的数据成员并定义对象的行为。</p><p>这部分我们会在后续章节类和对象中为大家详细讲解，这里只做点睛之笔（你可以点击 3.1.4-1 成员函数处的上标5，在脚注处我举了一个通俗易懂的成员函数的例子）。</p><p>类定义了如何表示和控制数据，成员函数归类所有。例如类 ostream 中有一个叫做 put() 的函数，用于输出字符，但类只能通过特定对象（这里是 cout 对象）来使用成员函数。要通过对象 cout 来使用成员函数，就必须使用点来将对象名和成员函数所连接。这个点（更准确叫句点）被称为成员操作符。而 cout.put() 的意思是通过类对象 cout 访问（或使用）成员 put() 函数。如本段开头所说，我们会在后续章节详细介绍这一点，现在我们接触过的类只有 istream/ostream（iostream），现在你可以通过使用他们的成员函数来熟悉这一概念。</p><h3 id="314-2-char-常量"></a> 3.1.4-2 char 常量</h3><p>在 C++ 中字符常量有很多种书写方式。对于常规字符(如字母、标点符号和数字)，最简单的方法是将字符用单引号引起来。这种表示法代表的是字符的数值编码。例如 ASCII 系统中对应的情况：</p><ul><li>‘A’ 为 65，即字符 A 的 ASCII 码。</li><li>‘a’ 为 97，即字符 a 的 ASCII 码。</li><li>‘1’ 为 49，即数字 1 的 ASCII 码。</li><li>‘!’ 为 33，即字符 ! 的 ASCII 码。</li><li>’ ’ 为 32，即空格的 ASCII 码。</li></ul><p>这种表示方法优于数值编码，它更加清晰，且不需要知道编码方式。如果系统使用的是非 ASCII 编码，则 A 的编码将不是 65 ，但 ‘A’ 表示的仍然是字符 A。</p><p>当然有些字符不能直接通过键盘输入到程序当中。例如：在程序中想要输出一个换行，我们并不能通过 Enter 键让字符串进行换行。因为编辑器会把这种操作视为编辑另起一行。再例如：我们不能把双印号用来分割字符串或者对一个词组打引号，因为 C++ 对这些字符提供了一种特殊的含义，第一个双引号代表字符串开始，第二个双引号代表字符串截止，如果字符串中间出现一个双引号，程序将会认为是两个字符串，且第二个字符串没有正常结尾。</p><p>但 C++ 提供了一种特殊的表示方法 —— <strong>字符转义</strong>，如下表所示。例如：<code>\n</code> 表示换行符，<code>\&quot;</code> 会将双引号作为常规的字符，而不是字符串分隔符。</p><details class="folding-tag" cyan open><summary> 字符转义表 (点击收起) </summary>              <div class='content'>              <table><thead><tr><th style="text-align:center">字符名称</th><th style="text-align:center">ASCII符号</th><th style="text-align:center">C++代码</th><th style="text-align:center">十进制ASCII码</th><th style="text-align:center">十六进制ASCII码</th></tr></thead><tbody><tr><td style="text-align:center">换行符</td><td style="text-align:center">LF（\n）</td><td style="text-align:center"><code>&quot;\n&quot;</code></td><td style="text-align:center">10</td><td style="text-align:center">0x0A</td></tr><tr><td style="text-align:center">回车符</td><td style="text-align:center">CR（\r）</td><td style="text-align:center"><code>&quot;\r&quot;</code></td><td style="text-align:center">13</td><td style="text-align:center">0x0D</td></tr><tr><td style="text-align:center">水平制表符</td><td style="text-align:center">HT（\t）</td><td style="text-align:center"><code>&quot;\t&quot;</code></td><td style="text-align:center">9</td><td style="text-align:center">0x09</td></tr><tr><td style="text-align:center">垂直制表符</td><td style="text-align:center">VT（\v）</td><td style="text-align:center"><code>&quot;\v&quot;</code></td><td style="text-align:center">11</td><td style="text-align:center">0x0B</td></tr><tr><td style="text-align:center">退格符</td><td style="text-align:center">BS（\b）</td><td style="text-align:center"><code>&quot;\b&quot;</code></td><td style="text-align:center">8</td><td style="text-align:center">0x08</td></tr><tr><td style="text-align:center">换页符</td><td style="text-align:center">FF（\f）</td><td style="text-align:center"><code>&quot;\f&quot;</code></td><td style="text-align:center">12</td><td style="text-align:center">0x0C</td></tr><tr><td style="text-align:center">响铃符</td><td style="text-align:center">BELL（\a）</td><td style="text-align:center"><code>&quot;\a&quot;</code></td><td style="text-align:center">7</td><td style="text-align:center">0x07</td></tr><tr><td style="text-align:center">反斜杠</td><td style="text-align:center">\</td><td style="text-align:center"><code>&quot;\\&quot;</code></td><td style="text-align:center">92</td><td style="text-align:center">0x5C</td></tr><tr><td style="text-align:center">单引号</td><td style="text-align:center">’</td><td style="text-align:center"><code>&quot;\'&quot;</code></td><td style="text-align:center">39</td><td style="text-align:center">0x27</td></tr><tr><td style="text-align:center">双引号</td><td style="text-align:center">&quot;</td><td style="text-align:center"><code>&quot;\&quot;&quot;</code></td><td style="text-align:center">34</td><td style="text-align:center">0x22</td></tr><tr><td style="text-align:center">空字符</td><td style="text-align:center">NUL</td><td style="text-align:center"><code>&quot;\0&quot;</code></td><td style="text-align:center">0</td><td style="text-align:center">0x00</td></tr></tbody></table>              </div>            </details><p>下面来看看我们如何使用转义字符。</p><div class="note info modern"><p>我们应该像处理常规字符时一样来处理转义字符。也就是说，将他们视为字符常量时应该使用单引号引起来，将他们放在字符串中时，不要使用单引号。</p></div><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">char</span> escapeChar = <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;Hello&quot;</span> &lt;&lt; escapeChar &lt;&lt; <span class="string">&quot;World&quot;</span>&lt;&lt; \t &lt;&lt;<span class="string">&quot;\&quot;Here\&quot; we are&quot;</span>;</span><br></pre></td></tr></table></figure><p>它的输出如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Hello</span><br><span class="line">World    &quot;Here&quot; we are</span><br></pre></td></tr></table></figure><h3 id="314-3-signed-char-和-unsigned-char"></a> 3.1.4-3 signed char 和 unsigned char</h3><p>与 int 不同的是 char 在默认情况下既不是没有符号，也不是有符号的。是否有符号是由 C++ 实现决定的，这样编译器开发人员可以最大限度的与硬件属性所匹配。如果 char 有某种特定的行为，你则可以显示的将类型设置为 <code>signed char</code> 或 <code>unsigned char</code>。</p><p>例如：当适用于需要表示有符号的小整数的情况，比如在处理一些小范围的温度变化值（可能有正有负）、误差值等场景时，可以使用 <code>signed char</code> 来存储温度的变化量（假设精度合适）。而当用于存储原始字节数据，比如图像、音频等文件的字节流数据。因为这些数据通常是无符号的字节序列，用 0～255 表示不同的颜色强度（在图像中）或者音频样本的幅度时，可以存储在 <code>unsigned char</code> 类型的变量中。</p><h3 id="314-4-wcha_t"></a> 3.1.4-4 wcha_t</h3><p><code>wchar_t</code> 是 C++ 中的宽字符类型。它用于表示比普通字符（char）更宽的字符编码，主要是为了处理 Unicode 字符或其他多字节字符集。在一些需要处理国际化文本（如包含多种语言字符）的程序中非常有用。例如，许多非英语语言有字符不能用单个字节（char）来准确表示，像中文、日文、韩文等语言的字符，这时候就需要使用 wchar_t 来存储。</p><p>wchar_t 的大小不是固定的，它取决于编译器和操作系统。在大多数现代系统中，wchar_t 通常占用 2 个字节或者 4 个字节。例如，在 Windows 操作系统下，wchar_t 一般是 16 位（2 个字节），用于存储 UTF-16 编码的字符；而在一些 Unix/Linux 系统中，则可能是 32 位（4 个字节），用于存储 UTF-32 编码的字符。 它存储的是字符的编码值。例如，对于一个 Unicode 字符，其对应的编码会存储在 wchar_t 变量中。如果是 UTF-16 编码，每个 wchar_t 可以存储一个 16-bit 的 Unicode 码点；如果是 UTF-32 编码，每个 wchar_t 可以存储一个 32-bit 的 Unicode 码点。</p><p>要声明一个 wchar_t 类型的变量，可以像这样：wchar_t myWideChar;。要定义一个宽字符常量，需要在字符前面加上L前缀。例如：<code>wchar_t wc = L'A';</code> 表示一个宽字符常量 A。如果要表示一个非英文字符，如汉字“我爱编程”，可以写成 <code>wchar_t chineseChar = L'我爱编程';</code>（这里假设 wchar_t 的大小和编码方式能够正确表示这个汉字）。</p><p>而对于宽字符串，可以使用 <code>wcslen</code>（计算宽字符串长度）、<code>wcscpy</code>（复制宽字符串）等函数。这些函数和处理普通字符串（char 类型）的函数类似，但用于宽字符环境。例如：</p><figure class="highlight c++"><figcaption><span>程序代码3-2</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cwchar&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">wchar_t</span> wstr[] = <span class="string">L&quot;Hello, 世界&quot;</span>;</span><br><span class="line">    <span class="type">int</span> length = <span class="built_in">wcslen</span>(wstr);</span><br><span class="line">    wcout &lt;&lt; <span class="string">L&quot;宽字符串长度为: &quot;</span> &lt;&lt; length &lt;&lt; std::endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在程序代码3-2中，我们使用 <code>wcslen</code> 函数计算了包括非英文字符在内的宽字符串的长度，<code>wcout</code> 用于输出宽字符流，它类似于 <code>cout</code>，但用于宽字符。</p><h2 id="315-bool-类型"></a> 3.1.5 Bool 类型</h2><p>这里我们只简单介绍 C++ 中布尔值的发展起源，至于使用，我们会在后续章节中多次且重点的使用到，届时我们将会向你着重强调用法及要点。</p><p>C++ 语言是在 C 语言的基础上发展而来的。在早期的 C 语言（C89 及以前版本）中没有布尔（<code>bool</code>）类型。C 语言中通常使用整数类型（如int）来表示逻辑值，其中 0 表示假（false），非零值表示真（true）。这种方式虽然能够实现逻辑判断，但在代码的可读性方面存在一定的不足。布尔类型随着 C++ 标准的发展而引入。从 C++98 标准开始，正式添加了 <code>bool</code> 类型。这使得程序员能够更清晰、更符合逻辑地处理布尔值相关的操作。</p><div class="note info modern"><p>任何数值和指针都可以被隐式转换为布尔值。任何非零值都被转换为 true，任何零值将会被转换为 false。</p></div><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>内存分为不同的区域，比如栈空间、堆空间等。在程序运行过程中，局部变量通常存储在栈上，动态分配的内存通常在堆上。当程序执行完毕，操作系统会回收程序所占用的内存资源，这些内存中的数据通常会被清除。也有一些特殊情况，比如某些操作系统可能会采用一些技术来缓存部分内存内容，或者某些恶意软件可能会尝试在程序结束后从内存中窃取信息，但从正常的程序设计和运行角度来说，程序结束后，内存中的绝大部分信息会被认为是丢失的。 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>在 C++ 11 标准中，引入了 long long 这种新的整数数据类型。虽然一些编译器可能已经支持 long long 作为扩展类型，但它并不是 C++ 标准所规定的类型。C++11 标准将其纳入，使其成为合法的、被标准认可的类型。 <a href="#fnref2" class="footnote-backref">↩︎</a></p></li><li id="fn3" class="footnote-item"><p>例如将“人”作为“一个类”，他所可能包含的“成员属性”包括：姓名、身高、年龄等，用法（<a href="http://person.name">person.name</a>()、person.height()、person.age()）。 <a href="#fnref3" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">C++数据类型全面指南：深入解析整型、浮点型、字符型和布尔型等基本数据类型。了解变量命名规则、内存分配原理、数据类型选择策略以及ASCII编码系统，掌握C++编程基础核心概念。适合C++初学者和需要巩固基础的程序员学习参考。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
  <entry>
    <title>《Hello C++》第 3 章 数据操作</title>
    <link href="https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3_DataOperation/"/>
    <id>https://blog.yujiay.wang/bookHelloCpp/HelloCpp/3_DataOperation/</id>
    <published>2025-11-11T08:00:00.000Z</published>
    <updated>2025-11-11T08:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<div class="note blue anzhiyufont anzhiyu-icon-sanmingzhi flat"><ul><li>C++ 变量的命名规则；</li><li>C++ 内部整型变量；</li><li>C++ 内部浮点型变量；</li><li>使用 const 限定符来创建符号常量；</li><li>C++ 的算术操作符；</li><li>自动类型转换；</li><li>强制类型转换。</li></ul></div><p>数据是编程语言的灵魂载体，它赋予了代码生命的律动，如同繁星照亮编程语言的浩瀚苍穹。</p>]]></content>
    
    
    <summary type="html">探索C++编程基础：第3章“数据操作”详解，涵盖简单变量类型、const常量、浮点类型、算数操作符、操作符重载及类型转换等核心概念。适合初学者系统学习C++数据操作技巧，提升编程效率。本博客提供实用示例与常见问题解答，助你快速掌握关键知识点。</summary>
    
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/categories/bookHelloCpp/"/>
    
    
    <category term="Hello C++" scheme="https://blog.yujiay.wang/tags/HelloCpp/"/>
    
  </entry>
  
</feed>
