《码出高效》学习笔记与书中错误记录

简介: 今天在阅读《码出高效》的时候看到了一个问题,我也是第一次知道,而且有点颠覆我的认知。所以做了一些测试,并记录下来。 然而测试的结果发现,好像事实并不如书中说的那么简单。 问题是这样的: if (true) int x; for (; ; ) int y; while (true) int z; 这三句话,能通过编译吗,如果能,会给出 Warning 吗,如果不能,那么错误信息是什么。

今天在阅读《码出高效》的时候看到了一个问题,我也是第一次知道,而且有点颠覆我的认知。所以做了一些测试,并记录下来。

然而测试的结果发现,好像事实并不如书中说的那么简单。

问题是这样的:

if (true) int x;
for (; ; ) int y;
while (true) int z;

这三句话,能通过编译吗,如果能,会给出 Warning 吗,如果不能,那么错误信息是什么。

书中给出的答案是,不能通过编译,会给出 Declaration not allowed here 编译错误信息,并对此,书中解释为:

单语句在没有加大括号的情况下,声明的变量不可能再被使用,编译器认为没有任何意义。

Every declaration that introduces a name has a scope, in which they can be used.

我做了一些测试,发现事情好像并不是那么简单。


我一开始也是这样认为的。我本来以为,至少应该通过编译,最多是给一个 Warning 说 variable is never used

我比较好奇,除了 Java,其他语言会不会有同样的编译错误。

首先是是测试 C、C++、Java 是不是都对这句话有相同的结果。

先来看 C,测试环境是 CentOS 7.3 x64,GCC 版本是 gcc version 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC)。

image

C,不管是 ANSI C 还是 C99,都无法通过编译,直接给出 Error。

error: expected expression before ‘int’

image

如果加上大括号,那么能够通过编译,遇到大家常见的 Warning。

image

warning: unused variable ‘x’ [-Wunused-variable]

image

同样的结果在环境中(我测试环境是 CodeBlocks,Windows)得到了相同的结果。

image

image

我相信,CLion 等 IDE 也有一样的结果,如果没有,那么可能是 IDE 帮忙优化了,毕竟有些时候,写 C 代码漏 include 一些头文件,编译和运行的结果也是正确的(IDE 帮你自动补上了)。

原因稍后分析,下面继续测试。

C++。

image

结果是,编译通过,给出 Warning。

事实上与代码无关,即使是对刚才的 .c 文件,只要使用 g++ 编译器,也是通过的。

image

再来看 Java。

public class Main {
    public static void main(String args[]) {
        if (true) int jxtxzzw;
    }
}

如果是 Eclipse,直接给出错误。

image

强行运行,编译失败,无法运行。

image

Unresolved compilation problem: Syntax error on token “)”, Statement expected after this token at …

如果是 IDEA,会给出编译错误信息。

Declaration not allowed here

image

image

至于为什么 C 就不行呢?难道 C 的语法什么地方说了这是不合法的吗?闻所未闻啊?

但是既然 C 的编译器说不行,那肯定是 C 的哪个标准说了这是不合法的,如果这是真的,那么就不是作用域的问题,而是语法、文法的问题。

换句话说,如果 if (true) {int x;} 是合法的,那为什么 if (true) int x; 就不符合语法呢?

我查阅了很多资料(链接见文末),最后找到一个比较信服的答案——确实,根据 C 标准,这就是错的,彻底的语法错误。

首先来澄清一个概念,if 条件句后面,必须跟一个语句。

int x 是一个声明,Declaration。

int x = 10; 是一个定义,Definition。

{int x;} 或者 {int x = 10;} 由于有了 {},是一条语句,Statement。

这是 3 个完全不同的概念,也是绝大多数程序员从一开始就分不清的,而且也始终分不清,从来分不清。

所以,现在的问题的答案就很显然了,C 要求 if 后面是一条语句,然而文章一开始那种写法,是 Declaration,不是 Statement,所以语法就是错的。

这也印证了那句 Error:expected expression,我需要一个表达式。

表达式 Expression,显然是一句语句 Statement。

同时,这与 Eclipse 的报错信息是一致的——if 后面需要一个 Statement。( Statement expected after this token at … )

如果从这个角度考虑,那么,IDEA 的错误提示,Declaration not allowed 就不应该从变量作用域的角度考虑这里的变量声明不合法,而是应该理解成,这是一个 Declaration,而我需要一个 Statement,所以 Declaration 在这里是不被允许的。

这是一个 Declaration,而我需要一个 Statement,所以 Declaration 在这里是不被允许的

至于为什么 g++ 就可以,我想这个问题,可能和 为什么有些 IDE 这么写就可以通过编译,我猜想的是(是的,只是猜想,没有验证过),恐怕是这个编译器,包括绝大多数的 IDE,都自动优化了这个地方,把所有的 if 等语句后面,默认当作套上了大括号在处理,即使是单语句,也假装有了一个大括号作用域,然后再编译的。

所以,有些 gcc 的编译器,也有可能可以,但是从我的测试情况来看,MinGW、Cygwin、Windows、Window 的 Ubuntu 子系统、CentOS 下,gcc 都会给出 error。

I guess the counter-intuitive part of the question is: if this is correct C:
if (a == 1) { int b = 10;}
then why is this not also correct C?
if (a == 1) int b = 10;
I mean, a one-line conditional if statement should be fine either with or without braces, right?
The answer lies in the grammar of the if statement, as defined by the C standard. The relevant parts of the grammar I’ve quoted below. > Succinctly: the int b = 10 line is a declaration, not a statement, and the grammar for the if statement requires a statement after the conditional that it’s testing. But if you enclose the declaration in braces, it becomes a statement and everything’s well.
见: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 以及 https://www.quora.com/What-does-error-expected-expression-before-int-mean-in-C

目录
相关文章
|
4月前
|
人工智能 弹性计算 缓存
2026年阿里云服务器优惠力度大吗?阿里云特价服务器测评及对比
2026年阿里云服务器优惠力度大吗?阿里云特价服务器测评及对比:2026年国内主流云厂商都有特价云服务器,核心集中在新用户秒杀、新老同享低价、企业专属特惠三类活动,其中阿里云以“入门款直降90%+续费同价+长周期折扣”的组合,在稳定性与性价比上形成均衡优势,整体优惠力度处于第一梯队,适合个人、中小企业与AI团队长期使用。下面用大白话讲清主流活动、阿里云优惠力度与对比,帮你判断是否适配需求。
416 3
|
数据采集 Web App开发 数据挖掘
飞桨x昇腾生态适配方案:07_性能数据分析
本文介绍了性能调优的全流程,包括分析、定位与优化。通过 profiling 工具采集算子级性能数据,定位计算与调度通信瓶颈。针对计算时间过长问题,可通过升级算子或提交工单解决;调度优化则关注重复编译,关闭在线编译或使用 aclnn 算子可提升效率。数据采集使用 paddlepaddle 的 profiler 工具,结合 msprof 解析生成的性能数据,重点分析 op_statistic_*.csv 和 op_summary_*.csv 文件,通过关键字段(如 Ratio、Total Time、Task Duration 和 Task Wait Time)量化性能瓶颈并实施优化策略。
427 10
|
6月前
|
人工智能 安全 调度
当“超节点”成为算力新秩序,openEuler重构数智基础设施
随着AI迈向规模化应用,大模型算力需求激增,传统架构难以为继。超节点应运而生,打破“算力孤岛”,实现资源统一调度。openEuler携手产业伙伴,打造全球首个面向超节点的操作系统,推动国产系统从“替代”走向“引领”。2025年,操作系统大会释放强信号:AI与算力深度融合,openEuler 24.03 LTS SP3将于年底上线,2026年或成商业化元年。通过全局资源抽象、异构融合、低时延通信等能力,操作系统正成为智能时代的“神经中枢”。数千企业、数万开发者共建生态,openEuler装机量将破1600万套,加速AI普惠落地,重塑全球算力新格局。
340 11
|
存储 安全 编译器
第二问:C++中const用法详解
`const` 是 C++ 中用于定义常量的关键字,主要作用是防止值被修改。它可以修饰变量、指针、函数参数、返回值、类成员等,确保数据的不可变性。`const` 的常见用法包括:
|
9月前
|
Web App开发 存储 缓存
markdown编辑器
本Markdown编辑器基于StackEdit改进,新增界面设计、代码高亮、图片拖拽、KaTeX公式、甘特图、多屏编辑、写作模式切换、检查列表等功能,提升写作体验,支持离线使用与多种格式导出。
514 0
markdown编辑器
|
前端开发 JavaScript 测试技术
前端开发需要哪些技术
前端开发需要哪些技术【8月更文挑战第25天】
970 0
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页、INSERT INTO SELECT / FROM查询结合精例等详解步骤及常见报错问题所对应的解决方法
|
存储 数据处理 流计算
流模式vs批模式:你选对了吗?
本文由阿里云 Flink 团队刘文聪老师在撰写。文章分析了 Flink 的流批模式在不同维度存在的特点与差异,帮助开发者朋友们更好地理解 Flink 的流批模式。
990 12
流模式vs批模式:你选对了吗?
|
SQL 算法 数据库
sql数据库表内容误删怎么恢复
当SQL数据库表的内容误删时,可以尝试以下方法来恢复数据: 首先,最佳的解决方案是使用数据库备份来恢复数据。这是一种重要的防备措施,可在数据意外删除时快速恢复。 1. **使用备份恢复**
|
存储 机器学习/深度学习 JavaScript
技术经验分享:dTree树型组件详解
技术经验分享:dTree树型组件详解
246 0