《C专家编程》一1.6 它很棒,但它符合标准吗

简介:

本节书摘来自异步社区《C专家编程》一书中的第1章,第1.6节,作者 【美】Perter Van Der Linde,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.6 它很棒,但它符合标准吗

不要添乱——立即解散ISO工作小组。

——匿名人士

ANSI C标准可以说是非常独特的,我们可以从好几个有趣的方面来说明这一点。它定义了下面一些术语,用于描述某种编译器的特点。如果你对这些术语有一个比较好的了解,就有助于你理解什么东西能被语言接受,什么东西不能被语言接受。前两个术语涉及不可移植的代码(unportable code),接下来的两个术语跟坏代码(bad code)有关,而最后两个术语则跟可移植的代码(portable code)有关。

不可移植的代码(unportable code):

由编译器定义的(implementation-defined)——由编译器设计者决定采取何种行动(就是说,在不同的编译器中所采取的行为可能并不相同,但它们都是正确的),并作好文档记录。

例如:当整型数向右移位时,要不要扩展符号位。

未确定的(unspecified)——在某些正确情况下的做法,标准并未明确规定应该怎样做。

例如:参数求值的顺序。

坏代码(bad code):

未定义的(undefined)——在某些不正确情况下的做法,但标准并未规定应该怎样做。你可以采取任何行动,可以什么也不做,也可以发出一条警告信息,或者可以中止程序以及让CPU陷入瘫痪,甚至可以发射核导弹(只要你安装了能发射核弹的硬件系统)。

例如:当一个有符号整数溢出时该采取什么行动。

约束条件(a constraint)——这是一个必须遵守的限制或要求。如果你不遵守,那么你的程序的行为就会变成像上面所说的属于未定义的。这就出现了一种很有意思的情况:分辨某种东西是否是一个约束条件是很容易的,因为标准的每个主题都附有一个“约束(constraint)”小节,列出了所有的约束条件。现在又出现了一个更为有趣的情况:标准规定[5]编译器只有在违反语法规则和约束条件的情况下才能产生错误信息!这意味着所有不属于约束条件的语义规则你都可以不遵循,而且由于这种行为属于未定义行为,编译器可以采取任何行动,甚至不必通知你!

例如:%操作符的操作数必须属于整型。所以,在非整数数据上使用%操作符肯定会引发一条错误信息。

不属于约束条件规则的例子:所有在C语言标准头文件中声明的标识符均保留,所以不能声明一个叫作malloc()的函数,因为在标准头文件里已经有一个函数以此为名。但由于这个规定不是约束条件,因此可以违反它,而且编译器甚至可以不警告你!关于“interpositioning”这一小节的更多内容,参见第5章。


1744f65d1127c9e86d0fa3cfd9afc8ba33245468

未定义的行为在IBM PC中引起CPU瘫痪!

未定义的软件行为引起CPU瘫痪的说法并不像它乍听上去那样牵强。

IBM PC的显示器以显示控制芯片所提供的水平扫描速率工作。回扫变压器(flyback transformer,一种产生高电压的装置,用于加速电子以点亮显示器上的荧光物质)需要保持一个合理的频率。

然而在软件中,程序员有可能把视频芯片的扫描速率设置成零,这样就会产生一个恒定的电压输出到回归变压器的输入端。这就使它起了电阻器的作用,只是把电能转换成热能,而不是传送到屏幕。这会在数秒之内就把显示器烧毁,那就是未定义的软件行为会导致系统瘫痪的理由。
可移植的代码(portable code):

严格遵循标准的(strictly-conforming)—— 一个严格遵循标准的程序应该是:

只使用已确定的特性。

不突破任何由编译器实现的限制。

不产生任何依赖由编译器定义的或未确定的或未定义的特性的输出。

这样规定的主要目的就是最大限度地保证可移植性。这样,不论你在什么平台上运行严格遵循标准的程序都会产生相同的输出。事实上,在所有遵循标准的程序中,属于这一类的程序并不多。例如,下面这个程序就不是严格遵循标准的:

#include <limits.h>
#include <stdio.h>
int main() { (void)printf("biggest int is %d", INT_MAX); return 0;}

/*并不严格遵循标准:其输出结果是由编译器定义的。*/

在本书的剩余部分,我们通常并不强求例子程序严格遵循标准。因为如果这样做会使文本看上去比较乱,而且不利于理解所讨论的要点。程序的可移植性是非常重要的,所以在你的现实编码中,应该始终要保证加上必要的类型转换、返回值等。

遵循标准的(conforming)——一个遵循标准的程序可以依赖一些某种编译器特有的不可移植的特性。所以,一个程序有可能在一个特定的编译器里是遵循标准的,但在另一个编译器里却是不遵循标准的。它可以进行扩展,但这些扩展不能修改严格遵循标准的程序的行为。但是,这个规则并不是一个约束条件,所以对于你的程序中不遵循标准之处,你不要指望编译器会给出一条警告信息指出你违反了规定!

上面所举的几个程序实例都是遵循标准的。

相关文章
|
1月前
|
Kubernetes 应用服务中间件 API
【重磅推荐】告别Ingress NGINX后,我们的思考和建议
K8s社区宣布Ingress NGINX将于2026年3月正式退役:虽API仍受支持,但停止更新与安全修复。主因是高危漏洞频发(如CVE-2025-1974)、维护者严重不足及架构技术债沉重。推荐生产环境平滑迁移至阿里云ALB Ingress——免运维、高SLA、兼容NGINX注解,并迈向Gateway API标准化未来
428 2
|
2月前
|
运维 自然语言处理 IDE
Claude Opus 4.6进入“双模式时代”:企业是否需要选择“快速模式”?
大模型成熟后,企业关注点转向效率、可控性与规模化部署。Anthropic推出Claude Opus 4.6“快速模式”,形成双结构设计。本文从企业视角解析:何时需要快速模式、是否真正降本、如何在云架构中放大价值,揭示双模式正成为高端模型工程化新标配。
|
10月前
|
机器学习/深度学习 存储 算法
如何判断两张图片的相似度?原来图片对比也可以如此简单!
本文介绍了图片对比技术在多个场景中的应用,如图片去重、内容审核、版权维权及相似图片搜索,并详细解析了两种主流的图片对比方法。第一种是**MD5指纹对比**,适合精确匹配完全相同的图片,具有速度快、简单易用的特点,但对稍作修改的图片无能为力。第二种是**图像哈希对比**,包括平均哈希、感知哈希等算法,能够判断图片的相似程度,适用于处理缩放、旋转或亮度调整后的图片,但在语义相似性上仍有局限。最后提到,随着机器学习和深度神经网络的发展,图片相似度判断技术将有更多可能性,值得进一步探索。
3247 6
如何判断两张图片的相似度?原来图片对比也可以如此简单!
|
人工智能 算法 网络安全
基于PAI+专属网关+私网连接:构建全链路Deepseek云上私有化部署与模型调用架构
本文介绍了阿里云通过PAI+专属网关+私网连接方案,帮助企业实现DeepSeek-R1模型的私有化部署。方案解决了算力成本高、资源紧张、部署复杂和数据安全等问题,支持全链路零公网暴露及全球低延迟算力网络,最终实现技术可控、成本优化与安全可靠的AI部署路径,满足企业全球化业务需求。
|
4月前
|
人工智能 运维 供应链
电子制造出海WAN服务:如何让技术/运维团队成为业务战略引擎?
FusionWAN NaaS为全球化电子制造企业提供智能广域网解决方案,降低网络成本30%以上,运维效率提升70%,SLA高达99.99%。应对跨境波动、多云复杂性等挑战,实现全球组网、多云互联、网络加速与一线多用,助力企业构建高效、稳定、合规的数字基础设施,推动网络团队从成本中心迈向价值创造核心。
|
6月前
|
人工智能 安全 架构师
2025云栖大会 | 阿里云网络技术Session主题资料和视频回放归档
2025年9月24日-26日,杭州,一年一度的云栖大会如期而至;阿里云飞天洛神云网络作为阿里云计算的连接底座,是飞天云操作系统的核心组件,致力于为上云企业提供高可靠、高性能、高弹性、智能的连接服务。本次云栖,云网络产品线也带来全系列产品升级,以及创新技术重磅解读,围绕增强确定性、提效自动化、深耕智能化和敏捷全球化带来技术、产品和服务升级,以及全新的云网络产品生态合作计划发布。
837 4
|
7月前
|
存储 运维 数据可视化
短剧为什么比长剧更依赖云和网络?
微短剧对云与网络的依赖远高于传统影视,因其制作周期短、投流驱动强、数据量大、IT团队轻量化及出海需求迫切。短剧的成功离不开高速传输、实时数据反馈、多云互联与跨境合规传输。一套理想的云网方案应具备高速文件传输、多云互联、跨境加速与合规、实时数据回传及可视化管理能力,助力短剧企业快速响应市场、提升投放效率、实现全球化分发。
|
容灾 关系型数据库 数据库
阿里云RDS服务巴黎奥运会赛事系统,助力云上奥运稳定运行
2024年巴黎奥运会,阿里云作为官方云服务合作伙伴,提供了稳定的技术支持。云数据库RDS通过备份恢复、实时监控、容灾切换等产品能力,确保了赛事系统的平稳运行。
 阿里云RDS服务巴黎奥运会赛事系统,助力云上奥运稳定运行
|
存储 缓存 索引
从底层数据结构和CPU缓存两方面剖析LinkedList的查询效率为什么比ArrayList低
本文详细对比了ArrayList和LinkedList的查询效率,从底层数据结构和CPU缓存两个方面进行分析。ArrayList基于动态数组,支持随机访问,查询时间复杂度为O(1),且CPU缓存对其友好;而LinkedList基于双向链表,需要逐个节点遍历,查询时间复杂度为O(n),且CPU缓存对其帮助不大。文章还探讨了CPU缓存对数组增删操作的影响,指出缓存主要作用于读取而非修改。通过这些分析,加深了对这两种数据结构的理解。
314 2
面试还在被红-黑树虐?看完这篇轻松搞定面试官(二)
面试还在被红-黑树虐?看完这篇轻松搞定面试官
面试还在被红-黑树虐?看完这篇轻松搞定面试官(二)