Review on C Programming Language

1. GCC命令的使用

  单个文件,一步到位:

    gcc ./src/test.c -o ./bin/test -I ./include -std=gnu99

  多个文件,一步到位:

    gcc ./src/test.c ./src/other.c -o ./bin/test -I ./include -std=gnu99

  相当于先逐个编译,再一步链接:

    gcc -c ./src/test.c -o ./test.o -I ./include -std=gnu99
    gcc -c ./src/other.c -o ./other.o
    gcc ./test.o ./other.o -o ./bin/test

  根据CSAPP,该过程详细分为四步:

  Step 1. Preprocessing  

  这一步将头文件嵌入源代码文件(库包含),并将代码中的宏名进行替换。Linux系统默认头文件目录为/usr/include/,默认库文件目录为/usr/lib/(用以实现头文件的接口)。引用系统默认目录中的头文件时可用单书名号声明文件名;若欲引用非系统默认目录中的头文件,则须使用引号声明文件名,且在不使用-I参数时默认头文件目录为gcc当前工作目录(不一定是源代码目录)。

    gcc -E ./src/test.c -o ./test.i -I ./include

  Step 2. Compilation

  这一步根据运行环境生成汇编代码,可选用C99。

    gcc -S ./test.i -o ./test.s -std=gnu99

  Step 3. Assembly

  这一步由汇编代码生成对象文件。

    gcc -c ./test.s -o ./test.o

  Step 4. Linking

  这一步将(多个)对象文件与库文件链接在一起。

    gcc ./test.o ./other.o -o ./bin/test

2. 语法中的细节

  (1) ANSI C中任何语句块开头都可以定义变量(课设里也是这样实现的~~)。

  (2) 定义char尽量声明为 signed char 或 unsigned char,定义int尽量声明为 signed short 或 signed long。

  (3) static和extern型的变量被缺省初始化为0;任何数组若被提供少于其长度的初始值,则剩余元素被缺省初始化为0,因此有个开数组并赋初值的技巧是:

    int arr[1024] = {};

  (4) 声明无参数函数时要显式使用void关键字。

  (5) 多个运算表达式可用逗号隔开,自左向右依次求值:

// call swap(&x,&y)
void swap(int *x, int *y)
{
    x += y, y = x-y, x -= y;
}

  (6) 尽量不要在同一表达式中调用多个函数或向同一函数中传入多个函数值,因为表达式求值与函数传参顺序依赖于运行环境,而由于全局变量的存在函数调用顺序不同可能造成运行结果不同(以前在C++输出流中犯过类似的错误,调了一晚上)。

  (7) 有参宏定义中,给宏展开里的形参前加#可使其在被替换时被引号包裹,并且替换时会自动为实参中的\和"等符号添加转义符号:

#define STR(str) #str    // STR(Hello!) will be replaced by "Hello!"

  (8) 有参宏定义中,用##可将参数嵌入到字符串当中:

#define FUN(name) Hello,##name##!

  (9) 多行宏定义举例:

#define min(X,Y) ({    typeof(X) x_ = (X);    typeof(Y) y_ = (Y);    (x_ < y<)? x_:y_;})

  (10) 防止头文件被重复包含:

#ifndef HEADER_H
#define HEADER_H

/* content of header.h */

#endif

  (11) 条件编译举例:

#if NUM_OF_ATOM == 1
    #define FREDEG 3
#elif NUM_OF_ATOM == 2
    #define FREDEG 5
#else
    #define FREDEG 6
#endif

  (12) C语言中,一个指针在内存中占据8字节,记录着指向区域的首地址(是虚拟地址,并不是什么数据段偏移量,以前弄错了T_T);其指向区域的大小由其本身类型决定,只在编译期间被符号表记录。对于一个数组 int arr[1024],&arr[0]、arr与&arr指向相同首地址,但后者与前两者类型不同,因此编译器计算 (&arr+1) 时会得出与 (arr+1) 和 (&arr[0]+1) 完全不同的结果(指针加一实际上是指针值加一倍的指向数据的长度,即 sizeof(*ptr))。另外,尽管数组名在参与加减运算时被当做指向数组首元素地址的常指针,但 sizeof(arr) 和 sizeof(&arr[0]) 并不相同。

  (13) 参数分为输入参数和输出参数:输入参数为值传递,通常放在前边;输出参数以指针或数组形式传递,通常放在后边。

  (14) const char *ptr为常量指针,表明不可以通过ptr修改其指向的内存区域;char* const ptr为指针常量,表明ptr不可改变指向的内存区域。

  (15) 函数指针形式为int (*comp) (int,int),常作为函数参数。

  (16) 数据段有三种变量:第一种是全局变量,可以被其他源文件(以及本文件该变量声明前的函数)以外部变量方式引用;第二种是静态全局变量,作用域为本文件该变量声明之后的函数;第三种是静态局部变量,作用域为声明该变量的函数(可以不是静态函数)。

  (17) 字符串常量属于指令的一部分,存储在代码段,因此以字符指针形式修改其中的字符就会造成 segmentation fault;但初始化为字符串常量的字符数组却不同,因为数组初始化已将指令中的常量拷贝到了数据段或堆栈段分配给该数组的空间。

  (18) 结构体占用空间不一定等于各成员所占空间之和,因为成员之间可能存在空穴。

===========================================================

  博主最近在某无聊通识课上写51单片机程序控制开环小车走固定路线,为了能够随时调整每一段路程的运行时间,用了以下代码所展示的技巧:

 1 void main(void)
 2 {
 3     Int16U data runTimeCnt = 0;
 4     Int8U data point;
 5
 6     /* some initializations, omitted here */
 7
 8     while (1) {
 9         runTimeCnt++;
10         do {
11             point = time0;
12             if (runTimeCnt<point) {
13                 go_straight();
14                 break;
15             }
16             point += time1;
17             if (runTimeCnt<point) {
18                 turn_right();
19                 break;
20             }
21             point += time2;
22             if (runTimeCnt<point) {
23                 go_straight();
24                 break;
25             }
26             point += time3;
27             if (runTimeCnt<point) {
28                 turn_left();
29                 break;
30             }
31             point += time4;
32             if (runTimeCnt<point) {
33                 go_straight();
34                 break;
35             }
36             rest();
37         } while(0);
38
39         /* remaining section, omitted here */
40
41     }
42 }

  由于改变控制的时间点point由各时间段动态计算得到,所以改起来格外方便。另外,最初我使用了goto语句,代码风格不是很好,在这里用 do...while(0) 进行了重构。

  然而,博主还是有所疏忽,真正运行的时候发现舵机并没有按预想的那样运行。后来发现原因在于point只分配8位内存明显不够,导致了加法溢出,幸好发现得及时,没有浪费太长时间进行调试。

时间: 2024-12-12 05:49:35

Review on C Programming Language的相关文章

Questions that are independent of programming language. These questions are typically more abstract than other categories.

Questions that are independent of programming language.  These questions are typically more abstract than other categories. Free Language Agnostic Programming Books 97 Things Every Programmer Should Know Algorithms and Data-Structures (PDF) Algorithm

Go语言自述(The Go Programming Language README)

声明:本文为笔者为练习英语所做的翻译练习,原文所属者与笔者没有任何关系,翻译结果不代表原文所属者的观点.笔者不保证翻译的正确性,任何人以任何形式的对本文的引用,都是不负责任和荒谬的行为,造成的后果笔者不予负责. 原文链接所属:golang/go Go is an open source programming language that makes it easy to build simple,reliable, and efficient software. Go是一门开源的编程语言,用它可

转:从《The C Programming Language》中学到的那些编程风格和设计思想

这儿有一篇写的很好的读后感:http://www.cnblogs.com/xkfz007/articles/2566424.html 读书不是目的,关键在于思考. 很早就在水木上看到有人推荐<The C Programming Language>这本书,一直都没看,开学一个月就专心拜读了一下,并认真做了课后习题.读来收获不少,主要有两点:一是加深了自己对一些基础知识的理 解和感悟:二是从中学到了一些不错的编程风格和设计思想,这些东西虽看起来不起眼但细细嚼来还是很值得学习的.下面就从四个方面做一

The Swift Programming Language (基础部分)

简介 Swift 是一门开发 iOS, OS X 和 watchOS 应用的新语言.然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的. Swift 包含了 C 和 Objective-C 上所有基础数据类型,Int表示整型值:Double和Float表示浮点型值:Bool是布尔型值:String是文本型数据.Swift 还提供了三个基本的集合类型,Array,Set和Dictionary,详见集合类型. 就像 C 语言一样,Swift

《The Swift Programming Language》的笔记-第24页

The Swift Programming Language读书笔记学习笔记 第24页 本页主要内容有两个:打印输出和如何在swift注释代码 1 如何打印变量和常量的值? 使用println函数,细节:println函数除打印变量常量值外还输出一个换行 1) 打印常量 eg1 let hw = "hello chinagame.me" println(hw) => 可将字符串常量输出到Console里 2) 打印变量, 双引号里用 \(变量名) 输出,这个像C语言里的%s eg

[iOS翻译]《The Swift Programming Language》系列:Welcome to Swift-01

本文转载至:http://www.cnblogs.com/yangfaxian/p/3765081.html 全书目录: 一.Welcome to Swift 二.Language Guide 三.Language Reference /* 译者的废话: 几个小时前熬夜看了WWDC,各种激动,今年很有料啊!当看到Swift出来的时候,瞬间傻眼,又要学习新语言了.这篇文章来自苹果官方的<The Swift Programming Language>一书,500页左右,在苹果官网有下载.Swift

The Swift Programming Language 中文版

iSwifting社区 Swift 兴趣交流群:303868520 iOS 微信公众账号:iOSDevTip Swift 微信公众账号:SwiftDev iSwifting社区 如果你觉得这个项目不错,请点击Star一下,您的支持我们最大的动力. The Swift Programming Language 中文版 这一次,让中国和世界同步 The Swift Programming Language 中文版,布布扣,bubuko.com

The Swift Programming Language IOS8 快捷编程语言

This is a preliminary document for an API or technology in development. Apple is supplying this information to help you plan for the adoption of the technologies and programming interfaces described herein for use on Apple-branded products. This info

The C Programming Language(K&R) 扣细节随记(施工中...

各种糟糕,入坑这么久才开始看K&R的The C Programming Language学C,而且还是为了应付开学某场滚回本体的考试(虽然觉着即使复习了还会被各种吊打),废话不多说,开始施工.? ? |--> 导言 整数除法会执行舍位,故要先乘后除. 数据类型: 关键字 位长(字节) 范围 格式化字符串 char 1 bytes -128..127(或0..255,与体系结构相关) ?%c unsigned char 1bytes 0..255 ?%c,?%hhu signed char 1