一、字符和字符串

1. Q:为什么strcat(string, '!')不行?

A:strcat()用于拼接字符串,所以应该写成strcat(string, "!")。"!"实际上包含两个字符:'!'和'\0'。

2. Q:为什么不能这样检查一个字符串是否跟某个值匹配?

char *string;
...
if (string == "value") {
/* string matches "value"*/
}

A:C语言中的字符串用字符的数组表示,C语言不会把数组作为一个整体来操作(赋值、比较等)。上面代码段的==操作符实际上比较的是两个指针是否相等,要比较两个字符串,一般使用库函数strcmp()。

3. Q:我正开始考虑多语言字符集的问题,是否有必要担心sizeof(char)会被定义为2,以便表达16位的字符集呢?

A:就算char型被定义为16位,sizeof(char)依然是1(sizeof是以char的大小作为一个单位的),而<limits.h>中的CHAR_BIT会被定义为16,届时将不能声明(或用malloc分配)一个8位的对象。

二、布尔表达式和变量

1. Q:C语言中布尔值该用什么类型?为什么它不是一个标准类型?

A:C语言中没有提供标准的布尔类型,部分原因在于选择一个这样的类型设计最好有程序员来决定的空间/时间折中。(使用int型可能更快,使用char型可能更节省数据空间。然而,如果需要和int型反复转换,那么更小的类型也可能生成更大或更慢的代码。)可以使用#define或枚举常量定义真假,无伤大雅。

#define TRUE  1
#define FALSE 0 enum bool {false, true};

2. Q:我使用了来自两个不同的第三方库的头文件,它们都定义了相同的宏,如TRUE, FALSE, Min(), Max()等,但是它们的定义相互冲突,怎么办?

A:这是个典型的命名空间问题。理想状态下,第三方库的厂商在定义符号(预处理库、全局变量和函数名称)的时候应该尽责地确保不会发生命名空间冲突,最好的解决方案是让厂商修改他们的头文件。作为一种迂回措施,你也可以在发生冲突的#include指令之间解除或重新定义冲突的宏。

三、C预处理器

1. 如果一个参数在宏扩展中出现了多次,而实参是带副作用的表达式,则宏可能不能正确运行。

#define square(x) ((x) * (x))
square(i++); //会被扩展为((i++)*(i++)),而这是未定义的

2. Q:如何书写多语句宏?

A:通常的目标时能够像一个包含函数调用的表达式语句一样调用宏:MACRO(arg1, arg2); 这意味着“调用者”需要提供最终的分号,而宏体不需要。因此宏体不能为简单的括号包围的复合语句,因为这个宏可能会用于带else的if/else语句的if分支。传统的解决方法是使用do-while语句。

#define MACRO(arg1, arg2) {stmt1; stmt2;}
if (cond)
MACRO(arg1, arg2);
else /* some other code*/ /*宏展开后,用户提供的最终的分号就会成为语法错误*/
if (cond)
{stmt1; stmt2;};
else /* some other code */ /* 传统的解决方案 */
#define MACRO(arg1, arg2) do { \
stmt1;
stmt2;
...
} while()

如果宏体内的语句都是简单语句(没有声明或循环),那么还有一种技术,就是写一个使用一个或多个逗号操作符的表达式,放在括号中:

#define FUNC(arg1, arg2) (expr1, expr2. expr3)  // FUNC返回expr3

有些编译器(如gcc)可以使用非标准的“inline”关键字或其他扩展自动地或根据程序员的请求使用内联扩展小函数。

3. Q:应该把哪些内容放在.h文件?哪些内容放在.c文件?

A:作为一般规则,应该把下面所列的内容放入头文件:(a)宏定义;(b)结构、联合和枚举声明;(c)typedef声明;(d)外部函数声明;(e)全局变量声明。

另一方面,如果定义或声明为一个源文件私有,则最好留在该文件中(并声明为static)。最后,不能把实际的代码或全局变量放在头文件中。

4. Q:可以在一个头文件中包含另一个头文件吗?

A:这是个风格问题。反对者认为,“嵌套包含文件”应该避免,因为它让相关定义更难找到。如果一个文件被包含了两次,它会导致重复定义错误,同时它也会令Makefile的人工维护十分困难。支持者认为,“嵌套包含文件”使模块化使用头文件成为可能(一个头文件可以包含它所需要的一切,而不是让每个源文件都包含需要的头文件)。而自动的Makefile维护工具可以很容易地处理嵌套包含文件的依赖问题。一种流行的头文件定义技巧:

#ifndef __HFILENAME_H__
#define __HFILENAME_H__
...
#endif

5. Q:完整的头文件搜索规则是怎样的?

A:准确的行为是由实现定义的(一般应该有文档说明)。通常,用<>命名的头文件会先在一个或多个标准位置搜索,用""命名的头文件会首先在“当前目录”搜索,如果没有找到再在标准位置搜索。注意“当前目录”的定义不唯一:传统上当前目录是包含#include指令的文件所在的目录,而在其他编译器下,当前目录是编译器启动的目录。

6. Q:sizeof操作符可以用在#if预处理指令中吗?

A:不行。预处理在编译过程之前进行,此时尚未对类型名称进行分析。作为替代,可以考虑使用ANSI的<limits.h>中定义的常量,或者使用配置脚本。当然,更好的方法是编写与类型大小无关的代码。

7. Q:如何用#if表达式来判断机器是高字节在前还是低字节在前?

A:恐怕不能。判断机器字节顺序的代码技术通常都要用到字符数组或联合,但预处理运算仅仅使用长整型,而且没有寻址的概念。另外,通常写出与字节顺序无关的代码更好。

《你必须知道的495个C语言问题》读书笔记之第8-10章:字符串、布尔类型和预处理器的更多相关文章

  1. 你必须知道的495个c语言问题(笔记)

    1.1我该如何决定使用哪种整数类型? 用到较大的数用long:空间很重要(例如有很大的数组或很多的结构)用short:此外用int. win32: int 32bit    4byte char 8b ...

  2. 你必须知道的495个C语言问题,学习体会一

    C语言作为一门古老的语言,其灵活性和容易出错都让人 又爱又恨,书籍<你必须知道的495个C语言问题>,使用问答的形式,告诉读者 C语言使用的各个方面的知识,包括一些冷知识等.以下,我要摘录 ...

  3. C语言学习书籍推荐《你必须知道的495个C语言问题》

    萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...

  4. 《你必须知道的495个C语言问题》知识笔记及补充

    1. extern在函数声明中是什么意思? 它能够用作一种格式上的提示表明函数的定义可能在还有一个源文件里.但在 extern int f(); 和 int f(); 之间并没有实质的差别. 补充:e ...

  5. 《你必须知道的495个C语言问题》读书笔记之第11-14章:ANSI C标准、库函数、浮点数

    一.ANSI C标准 1. ANSI向C语言预处理器引入了几项新的功能,包括“字符串化”操作符(#).“符号粘贴”操作符(##).#pragma指令. 2. Q:char a[3] = "a ...

  6. 《你必须知道的495个C语言问题》读书笔记之第1-2章:声明和初始化

    1. C标准中并没有精确定义数值类型的大小,但作了以下约束: (1) char类型可以存放小于等于127的值: (2) short int和int可以存放小于等于32767的值: (3) long i ...

  7. 你必须知道的495个C语言问题,学习体会四

    本文,我们来学习下指针,这是个梦魇啊.无数次折磨着C语言学习者,无数次的内存泄露,无数次的访问失败,无数次的越界溢出, 这些错误造就的仅仅是一个 跟随者,真正的优秀者必须要正视语言的局限,同时在最大限 ...

  8. 你必须知道的495个C语言问题,学习体会三

    本文是 本系列的第三篇,本文主要对C语言的表达式做个小结 先从两个坑爹的表达式说起:i++ 与++i 上大学的时候,学长告诉我,这两个表达式,意义是一样的,后来老师纠正说,还是有区别的,于是让我们记住 ...

  9. 你必须知道的495个C语言问题,学习体会二

    这是本主题的第二篇文章,主要就结构体,枚举.联合体做一些解释 1.结构体 现代C语言编程 结构化的基石,diy时代的最好代言人,是面向对象编程中类的老祖宗. 我们很容易定义一个结构体,比如学生: st ...

随机推荐

  1. 【算法进阶-康托展开】-C++

    目录 引入 这位老爷子就是康托 基本概念 康托展开是一个全排列到一个自然数的双射,常用于构建hash表时的空间压缩.设有n个数(1,2,3,4,-,n),可以有组成不同(n!种)的排列组合,康托展开表 ...

  2. MySQL 锁(lock与latch)

    一.什么是锁 锁机制用于管理对共享资源的并发访问,它是数据库系统区别于文件系统的一个关键特性. 数据库系统使用锁是为了支持对共享资源的并发访问,提供数据的完整性和一致性. InnoDB存储引擎锁的实现 ...

  3. learning express step(四)

    learning express route function const express = require('express'); const app = express(); app.get(' ...

  4. sizeof +数组名

    链接:https://www.nowcoder.com/questionTerminal/daa5422cb468473c9e6e75cc98b771de 来源:牛客网 sizeof一个数组名称的时候 ...

  5. [Luogu] 可持久化线段树 1(主席树)

    https://www.luogu.org/problemnew/show/P3834 #include<cstdio> #include<iostream> #include ...

  6. java生成zip包兼容Linux

    /* 这个方法只用在windows中用服务器为Linux就不行 */ package common.util; import java.io.File;import java.io.FileInput ...

  7. 【学习笔记】OI模板整理

    CSP2019前夕整理一下模板,顺便供之后使用 0. 非算法内容 0.1. 读入优化 描述: 使用getchar()实现的读入优化. 代码: inline int read() { int x=0; ...

  8. Apache Web服务器 安装步骤 和遇到的坑

    Apache Web服务器是开发放源码的网页服务器,我们看到的网页都是上传到服务器然后呈现给用户的. 在开发中,在自己的电脑上安装Apache Web服务器,你的电脑也会成为服务器,配置文件,访问你的 ...

  9. java设计模式简述

    1.代理模式:有一个接口或者顶层类(可以是抽象的)A,一个实现类B,一个代理类C,代理类C之所以能够是代理类,是因为1.C也实现了A.2.C持有A的依赖,用来注入真实的实现B.3.C的实现方法中实际调 ...

  10. Linux使用iptables设置黑白名单

    使用ipset工具 1,下面我先说下iptables的基本配置规则,然后再说ipset以下使用C7 x86_64为实验环境CentOS7默认的防火墙不是iptables,而是firewalle.如果你 ...