关闭

C001-C语言-语法与用法摘录-(ques=2)

标签: C语言基础C语言语法C语言用法C语言深度剖析
584人阅读 评论(0) 收藏 举报
分类:

本文摘录一些平时遇到的、需要留意的、C语言方面的语法和用法。

但不收录那些很少用到的不重要的地方,除非我觉得它有意思。


-------------------------------------------------------------------------------------------------------------------------------------

参考资料:

1、《C语言深度解剖》  2016.06

2、《让你不再害怕指针》  

3、


-------------------------------------------------------------------------------------------------------------------------------------

-4、


-------------------------------------------------------------------------------------------------------------------------------------

-3、全局变量限制只出现在一个文件中,提供专门的读写函数给外部文件操作这些变量。


-------------------------------------------------------------------------------------------------------------------------------------

-2、.注释要写"为什么这样写"、说明思路和作用

        .不用写"如何实现"、除非真的不易读,如公式推导而来的代码。


-------------------------------------------------------------------------------------------------------------------------------------

-1、./**/ 会被编译器用空格 " " 替换,所以 in/**/t i = 0; 会被编译器报错。

      ."\" 换行符/继续符后面不能有空格 " ",否则 "\" 会被编译器视为是转义符+空格 " " 而被编译器报错。

       同时要注意换行后、第二行可能会习惯性的先打空格,这些空格会被连接到第一行后面。

       如:#def\
                   ine
       会被连接成:#def    ine


-------------------------------------------------------------------------------------------------------------------------------------

0、stu.name 中的 "." 可以认为是从 stu 中取出指定的偏移 name


-------------------------------------------------------------------------------------------------------------------------------------

1、bool 变量与 0 的比较

定义:      BOOL  b_flag = FALSE;
最好的写法:if(b_flag);                if(!b_flag);
可接受写法:if(b_flag == 1);           if(b_flag = 0);
有风险写法:if(b_flag == TRUE);        if(b_flag == FALSE);

解释:FASE的定义一般都是0,TRUE的定义一般是1或-1。

            也就是说FALSETRUE都是人为定义的,可能不都是0和1,尤其是TRUE


            另外、有的时候我们需要使用 不为0即是真 来作为判定条件。


-------------------------------------------------------------------------------------------------------------------------------------

2、浮点数之间的比较

浮点数之间的比较不能直接比较,要比较一个范围,因为浮点数存储时都是有误差的,不是原值。

DELTA用来指定比较的精度。


另外、差异很大的两个浮点数之间的运算,结果很可能是错的。


-------------------------------------------------------------------------------------------------------------------------------------

3、函数的参数不要多于4个

      否则CPU的处理效率会降低,参数多了可以用struct打包。

-------------------------------------------------------------------------------------------------------------------------------------

4、用typedef给类型重命名

(1).
    const int temp; 和 int const temp; 等价
(2).
    typedef  struct student 
    {
        int data;
        ...
    } stu_data, *stu_ptr;
    const  stu_data  temp; 和 stu_data  const  temp;  等价
    const  stu_ptr p_temp; 和 stu_ptr  const  p_temp; 等价

原因在于 typedef 定义的 stu_data stu_ptr 都是一个类型,对编译器来说、他们和 (1) 例中的 int 这个类型在地位上平等

因此编译器处理 stu_data  const  temp; stu_ptr  const  p_temp; 时,与处理 int const temp; 时的过程一致。

虽然在 stu_ptr 的定义中有指针符号 * ,但它不是独立的,而是和 struct student 绑定在一起的。

stu_ptr  const  p_temp;  和 struct  student const * temp;是不一样的:前者是 stu_ptr  const  类型的指针,后者是 struct  student 类型的const指针。


另外,虽然 stu_ptr 是一个类型,但 unsigned stu_ptr 却不能被编译器识别,因为编译器... ? 

|<----待解释-question-001


-------------------------------------------------------------------------------------------------------------------------------------
5、#define 常量表达式时、留意常量的范围
     
      #define 常量表达式时、留意常量的范围,数值较大时要用UL标记该宏为长整型。 ---- but why, if not .......
     GCC下要写为(356*24*60*60UL)UL放在括号外会被编译器报错。
      

-------------------------------------------------------------------------------------------------------------------------------------
6、#error之error-information 不用加双引号
      
      这里的 error-information 不用加双引号,加了就是字符串而已,报 error 时连双引号一起显示输出

     
      
      message来让编译器条件输出信息、辅助调试

     
     使用 #x x 和字符串区分开来,可以被 #define 的宏展开


-------------------------------------------------------------------------------------------------------------------------------------
7、数组a 的名字代表数组首元素a[0]的首地址,而不是整个数组的首地址
如:int a[5];
数组名a 作为一个地址使用时,代表的是a[0] 的首地址,因而*(a + 1) == a[1],因为(a + 1)是a 的地址加了一个元素大小的单位,是sizeof(a[0]) = 4 字节。
如果数组名a 是整个数组的首地址,而*(a + 1) 中的(a + 1) 是a 的地址加了整个数组大小的单位,是sizeof(a) = 20 字节,因此*(a + 1)  = a[5],而不是a[1]
但实际上,*(a + 1) == a[1] 才是对的,所以数组名a 是a[0] 的首地址。

另外,a是变量名, 在这里是这个数组的名字,和 int data; int *p = &data; 中的data一样、是整个变量的名字,所以&a 是取出整个数组的首地址。
&a 是整个数组a 的首地址,是相对于整个数组而言的,也就是说&a 这个地址值的类型是 int[5],它移动一个单位的大小是sizeof(a),因而(&a + 1)是加了sizeof(a) = 20 字节。
所以*(&a + 1) = a[5]

所以、int (*ptr)[5] = &a 是对的,而int (*ptr)[5] = a 是不对的,因为&a 的类型才是int [5] ,而a 的类型是int

另外,fun(a) fun(a[5]) 传递到函数的实参 是a 的首元素a[0] 的首地址 的备份。

-------------------------------------------------------------------------------------------------------------------------------------
8、函数返回的局部指针是野指针
函数内的局部变量是系统在栈空间分配的。
函数返回后,这个分配的区域被释放,这些地址就是用户程序不能访问的区域。

|<----待验证=question-002

-------------------------------------------------------------------------------------------------------------------------------------
9、malloc(0) 返回不可用的地址
      malloc(0) 在堆上申请空间A时,申请成功后会返回一个地址而不是NULL,但这个地址是无法使用的。
      结果是:if(NULL != pf) 这样的检查不起作用了。

     free(pf) 只是取消pf 对空间A 的使用权,而pf的值和空间A 中的内容都没变。

-------------------------------------------------------------------------------------------------------------------------------------
10、定义一个返回数组指针的函数
        由typedef 定义函数指针就可以知道怎么定义对应的函数了
        定义一个返回数组指针的函数,给出两种定义:
定义一:
typedef int(*pf_array_2(void))[2];  // 对应指针
int(*fun_return_pArray2(void))[2]
{
    int  temp[2] = {1, 2};
    int (*p)[2] = &temp;
    return p;
}
定义二:
typedef int(*p_array_2)[2];  // 定义返回值
p_array_2 fun_return_pArray2(void)
{
    int  temp[2] = {1, 2};
    int (*p)[2] = &temp;
    return p;
}
对应的外部申明:
typedef int(*p_array_2)[2];
extern p_array_2 fun_return_pArray2(void);

-------------------------------------------------------------------------------------------------------------------------------------
11、结构体变量初始化的理想通用方法
以前看过Python可以定义函数的默认参数,觉得挺方便。
今天想找类似方式给结构体变量初始化,找到了这篇文章,解决了我的需求:
现摘抄如下:
#include 

struct student_st
{
	char c;
	int score;
	const char *name;
};

static void show_student(struct student_st *stu)
{
	printf("c = %c, score = %d, name = %s\n", stu->c, stu->score, stu->name);
}

int main(void)
{
	// method 1: 按照成员声明的顺序初始化
	struct student_st s1 = {'A', 91, "Alan"};
	show_student(&s1);

	// method 2: 指定初始化,成员顺序可以不定,Linux 内核多采用此方式
	struct student_st s2 = 
	{
		.name = "YunYun",
		.c = 'B',
		.score = 92,
	};
	show_student(&s2);

	// method 3: 指定初始化,成员顺序可以不定
	struct student_st s3 = 
	{
		c: 'C',
		score: 93,
		name: "Wood",
	};
	show_student(&s3);
	
	return 0;
}
如果想初始化结构体数组,可采用 {{ }, { }, { }} 方式,如
struct student_st stus[2] = 
{
	{
		.c = 'D',
		.score = 94,
		/*也可以只初始化部分成员*/
	},
	{
		.c = 'D',
		.score = 94,
		.name = "Xxx"
	},
};

-------------------------------------------------------------------------------------------------------------------------------------

12、位域的类型

      位域的大小不仅和对齐方式有关,还和位域变量的类型有关
    struct student {
        unsigned char a1:4;
        unsigned int  b2:4;
        unsigned long c3:4,
                      c4:4;
        unsigned long long d4:4,
                           d5:4;
    }stu_charlotte;
    unsigned long      size_long;
    unsigned long long size_long_long;
    
    cout << "sizeof(size_long) = "      << sizeof(size_long)        << endl;
    cout << "sizeof(size_long_long) = " << sizeof(size_long_long)   << endl;
    cout << "sizeof(stu_charlotte) = "  << sizeof(stu_charlotte)    << endl;
      结果为:
                    sizeof(size_long) = 4
                    sizeof(size_long_long) = 8
                    sizeof(stu_charlotte) = 16
      也就是说:
                        1、d4、d5相当于是在一个8byte空间里面分配出的两个4bit区。
                        2、c3、c4 相当于是在一个4byte空间里面分配出的两个4bit区。

      而增加一个unsigned int变量后、由于对齐原因、结果将增大到24byte:
    struct student {
        unsigned char a1:4;
        unsigned int  b2:4;
        unsigned long c3:4,
                      c4:4;
        unsigned long long d4:4,
                           d5:4;
        unsigned int  number;
    }stu_charlotte;
    unsigned long      size_long;
    unsigned long long size_long_long;
    
    cout << "sizeof(size_long) = "      << sizeof(size_long)        << endl;
    cout << "sizeof(size_long_long) = " << sizeof(size_long_long)   << endl;
    cout << "sizeof(stu_charlotte) = "  << sizeof(stu_charlotte)    << endl;
      结果为:
                    sizeof(size_long) = 4
                    sizeof(size_long_long) = 8
                    sizeof(stu_charlotte) = 24
      原有的16byte、加上4byte的number,结果为20byte。
      而对齐模数为8,所以空间会变成24byte,以整除对齐模数8。

位域对齐参看:《A004-数据对齐的原因》
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
查看评论

C002-CPP-语法与用法摘录-(ques=0)

前言: 最近开始阅读《像程序员一思考》,需要使用C++,遂开始学习使用C++。 这里摘录一些需要记住的语法和错误,但不收录很少用到的特性,除非我觉得它很有意思。
  • Manon_des_source
  • Manon_des_source
  • 2016-06-14 22:48
  • 340

《人月神话》经典摘录

1 “人月”的欺骗 人们通常期望项目在接近结束时,软件项目能收敛的更快一些。然而,情况却是越接近完成,收敛得越慢。 产品在完成前总面临着陈旧过时的威胁,只有实际需要时,才能用到最新的构想。 缺乏合理的时间进度是造成项目滞后的最主要原因。 ...
  • ruoyiqing
  • ruoyiqing
  • 2014-08-23 11:26
  • 739

C001-C语言-函数集合

这是一个目录,标出了一些有用的函数。
  • Manon_des_source
  • Manon_des_source
  • 2016-06-03 23:12
  • 385

【C语言】语法--枚举

1 枚举解决了什么样的问题   枚举是提供了一个集合,以后如果需要取值的时候只能在这里面进行选取。比如我们选择星期几的这个参数 weekday = Monday等等,这就限定了变量的取值范围,使程序较少出错 2 定义方法(两种),类似于结构体的定义方法。  (1) ...
  • chenglibin1988
  • chenglibin1988
  • 2013-03-12 18:51
  • 1152

Delphi语法

单元 程序头:uses(子句列出了那些链接到程序的单元),block(声明,命令语句) 一个程序包括: • 一个程序头(program heading) • 一个uses 子句(可选),和 • 一个包含声明和命令语句的块(block) 一个单元以单元头(unit heading)开始,后面跟inte...
  • jiqimiao
  • jiqimiao
  • 2007-04-21 11:32
  • 1300

js语言的语法与c语言不同的地方小结

1.语句 1.for-in语句是一种精准的迭代语句,可以用来枚举对象的属性(枚举的意思是全部列出来的意思)
  • xiguabanhua
  • xiguabanhua
  • 2015-07-19 18:04
  • 1443

Windows系统命令行设置环境变量

set用于设置临时环境变量。只在当前命令行窗口中有效。setx用于设置用户环境变量和系统环境变量。默认设置是本地环境,通过选项 /m 设置系统环境变量。
  • leonliu06
  • leonliu06
  • 2017-11-20 21:18
  • 157

自编小工具:Collect-便利你的阅读摘录收集, 含源码,分享给大家

你是否已经厌烦频繁的切换窗口进行复制粘贴?你是否想要一个工具在不影响阅读连续性的情况下进行摘录? Collect,便利你的摘录,享受你的阅读。 性质: 完全免费,代码公开,无广告,无病毒,绿色,支持XP/WIN7/WIN8 功能: Collect模式下,在你进行阅读的时候,无论你使用的是...
  • lanbing510
  • lanbing510
  • 2015-03-20 13:46
  • 1504

C001-C语言-位运算应用集合

这里收录了一些位运算的应用。
  • Manon_des_source
  • Manon_des_source
  • 2016-06-03 23:20
  • 481

js中toFixed() 的用法

一、定义和用法 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。 语法 NumberObject.toFixed(num) 参       数 描述 num 必需。规定小数...
  • whaxrl
  • whaxrl
  • 2014-02-15 13:12
  • 840
    个人资料
    • 访问:38923次
    • 积分:782
    • 等级:
    • 排名:千里之外
    • 原创:42篇
    • 转载:1篇
    • 译文:0篇
    • 评论:3条
    最新评论