2014-07-29 11:38:30 xingyuaini 阅读数 46
  • 172集通俗易懂的C语言从入门到项目实战教程

    1) 本套课程针对高校大学生系统学习C语言而录制,从0基础入门讲起,循序渐进,通俗易懂,同时适用于计算机系及非计算机系的同学。通过学习可以帮助大家掌握C语言本质,轻松面对C语言全国二级考试,并达到能独立完成中型C项目、C游戏的水平; 2) 多数高校都开设了C语言课程,网上C语言课程也很多,但普遍存在两个问题: (1) 授课方式单一,大多是照着代码念一遍, 对刚刚接触编程的同学来说,感觉晦涩难懂 (2) 授课内容过度注重语法,没有项目实战支撑,造成课程枯燥无趣。本课程针对上述问题进行了改进 (1) 授课方式采用语法讲解+内存布局示意图+项目的方式,让课程生动有趣好理解 (2) 系统全面的讲解了C语言的核心技术点,还配套录制了《全国计算机二级C语言真题精讲》,让学员在掌握C语言编程的同时,还能轻松面对二级考试;3) 课程详细内容: 常量-变量、分支语句、循环语句、操作符和表达式、函数(库函数、自定义函数、递归调用 )、数组(一维数 组、二维数组、数组作为函数参数、指针数组)、指针(指针和指针类型、二级指针和多级指针、指针表达式解析、指针运算、数 组指针、函数指针、回调函数)、调试技巧、程序环境和预处理(翻译环境、运行环境、预定义符号、#define和#undef、宏和函 数、条件编译、文件包含)、 数据在内存中的存储、内存块分配、static、字符函数和字符串函数、自定义类型(结构体、枚举 、联合)、动态内存管理、文件操作(i/o常量、i/o函数、流)。

    73 人正在学习 去看看 张长志

#与##在宏定义中的--宏展开
#include <stdio.h>
#define f(a,b) a##b
#define g(a)   #a
#define h(a) g(a)
int main()
{
        printf("%s\n", h(f(1,2)));   // 12
        printf("%s\n", g(f(1,2))); // f(1,2)
        return 0;
}
宏展开时:
如果宏定义以#开头,不展开参数,直接替换。
故g(f(1,2))--->#f(1,2)--->"f(1,2)";
如果宏定义不以#开头,展开参数,直接替换,由外层向里层,如果碰到的是#开头的宏,不继续往里层展开,往外层展开。
由外层向里层,如果碰到的是以非#开头的宏,继续往里层走,直至最里层,开始一层层往外层展开。
故h(f(1,2))--->h(12)--->g(12)---->#12----->"12"。
PS:
##在宏中定义,是字符连接符
如a##b##c 等同于 "abc"
#在宏开头出现,是表示宏展开的方式不同
#a 等同于"a"
#abc 等同于 "abc"
复杂的:
#include <stdio.h>
#define f(a,b) a##b
#define g(a)   #a
#define h(a) g(a)
int main()
{
        char a = 'a';
        cout<<g(a)<<endl; // a
        cout<<g(g(a))<<endl; // a
        printf("%s\n", h(f(1,2)));   // 12
        printf("%s\n", g(f(1,2))); // f(1,2)
        printf("%s\n", g(h(f(1,2)))); // h(f(1,2))
        printf("%s\n", h(g(f(1,2)))); // "f(1,2)"
        printf("%s\n", h(h(f(1,2)))); // "12"
        system("pause");
        return 0;
}
预处理后的:(在编译选项中添加/EP /P后编译生成的.i文件
int main()
{
        char a = 'a';
        cout<<"a"<<endl;
        cout<<"g(a)"<<endl;
        printf("%s\n", "12");
        printf("%s\n", "f(1,2)");
        printf("%s\n", "h(f(1,2))");
        printf("%s\n", "\"f(1,2)\"");
        printf("%s\n", "\"12\"");
        system("pause");
        return 0;
}
---------------------------------------------------
宏解析
1.       ##操作符
##操作符它的作用是在替代表中将其前后的参数连接成为一个预处理符号,它不能出现于宏替代表的开端和末尾。
例:
#define concat(s,t) s##t
#define AAA ABC
concat(A, AA)
将被替换成
ABC
2.       重新扫描和替换
在替换列表中的所有参数替换过之后,预处理器将对结果token序列重新扫描以便对其中的宏再次替换。
当正在替换的宏在其替换列表中发现自身时,就不再对其进行替换。在任何正在嵌套替换的宏的替换过程中遇到正被替换的宏就对其不再进行替换(防止递归)。
例:
#define ROOT AAA CCC
#define AAA ROOT
ROOT
将被替换成
ROOT CCC

2018-06-17 11:05:47 xzwspy 阅读数 316
  • 172集通俗易懂的C语言从入门到项目实战教程

    1) 本套课程针对高校大学生系统学习C语言而录制,从0基础入门讲起,循序渐进,通俗易懂,同时适用于计算机系及非计算机系的同学。通过学习可以帮助大家掌握C语言本质,轻松面对C语言全国二级考试,并达到能独立完成中型C项目、C游戏的水平; 2) 多数高校都开设了C语言课程,网上C语言课程也很多,但普遍存在两个问题: (1) 授课方式单一,大多是照着代码念一遍, 对刚刚接触编程的同学来说,感觉晦涩难懂 (2) 授课内容过度注重语法,没有项目实战支撑,造成课程枯燥无趣。本课程针对上述问题进行了改进 (1) 授课方式采用语法讲解+内存布局示意图+项目的方式,让课程生动有趣好理解 (2) 系统全面的讲解了C语言的核心技术点,还配套录制了《全国计算机二级C语言真题精讲》,让学员在掌握C语言编程的同时,还能轻松面对二级考试;3) 课程详细内容: 常量-变量、分支语句、循环语句、操作符和表达式、函数(库函数、自定义函数、递归调用 )、数组(一维数 组、二维数组、数组作为函数参数、指针数组)、指针(指针和指针类型、二级指针和多级指针、指针表达式解析、指针运算、数 组指针、函数指针、回调函数)、调试技巧、程序环境和预处理(翻译环境、运行环境、预定义符号、#define和#undef、宏和函 数、条件编译、文件包含)、 数据在内存中的存储、内存块分配、static、字符函数和字符串函数、自定义类型(结构体、枚举 、联合)、动态内存管理、文件操作(i/o常量、i/o函数、流)。

    73 人正在学习 去看看 张长志

说明

#define命令将一个指定的标识符(即宏名)来代表一个字符串。可以分为两种:

简单的宏定义

#define 表示符 字符串

举例:

#define PI 3.14

float pi2 = PI * 2;   //pi2 = 6.28

带参数的宏定义

#define <宏名> (<参数表>) <宏体>

举例:

#define AddOne(x) (x+1)

float pi2 = PI * 2;    //pi2 = 6.28
pi2 = AddOne(pi2);     // pi2 = 7.28

不过,由于C++增加了内联函数(inline),实现起来比带参数的宏更方便,这样的宏在C++中已经很少使用了。

宏发生的时机

  1. 文件包含(#include命令)

    可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。

  2. 条件编译(#ifdef …. #def …. #endif命令)

    预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。

  3. 宏展开

    预处理器将源程序文件中出现的对宏的引用展开成相应的宏定义,即本文所说的#define的功能,由预处理器来完成。经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。

宏的特点

(1)宏名一般用大写,且末尾不加分号。

(2)宏定义的参数是无类型的,不做语法检查,不做表达式求解,只做替换。

(3)宏定义通常在文件的最开头,可以使用

```C++
#undef 宏名
```

命令终止宏定义的作用域。

(4)宏定义可以嵌套,但字符串”“中永远不包含宏。

(5)宏展开使源程序变长,函数调用不会;宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)。

(6)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存。

(7)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义,常量pi常用宏定义。

宏的优点:

  1. 提高了程序的可读性,同时也方便进行修改;

  2. 提高程序的运行效率:使用带参的宏定义既可完成函数调用的功能,又能避免函数的出栈与入栈操作,减少系统开销,提高运行效率;

  3. 宏是由预处理器处理的,通过字符串操作可以完成很多编译器无法实现的功能。比如##连接符。

宏的缺点

  1. 由于是直接嵌入的,所以代码可能相对多一点;

  2. 嵌套定义过多可能会影响程序的可读性,而且很容易出错;

  3. 对带参的宏而言,由于是直接替换,并不会检查参数是否合法,存在安全隐患。

常有宏定义

  1. 防止一个头文件被重复包含

    
    #ifndef BODYDEF_H
    
    
    
    #define BODYDEF_H
    
    
     //头文件内容
    
    #endif
    
  2. 得到指定地址上的一个字节或字

    
    #define MEM_B( x ) ( *( (byte *) (x) ) )
    
    
    
    #define MEM_W( x ) ( *( (word *) (x) ) )
    
    
    //例如:
    int bTest = 0x123456;
    
    byte m = MEM_B((&bTest));/*m=0x56*/
    int n = MEM_W((&bTest));/*n=0x3456*/
  3. 得到一个field在结构体(struct)中的偏移量

    
    #define OFFSETOF( type, field ) ( (size_t) &(( type * ) 0)-> field )
    
  4. 得到一个结构体中field所占用的字节数

    
    #define FSIZ( type, field ) sizeof( ((type * ) 0)->field )
    
  5. 得到一个变量的地址(word宽度)

    
    #define B_PTR( var ) ( (byte * ) (void * ) &(var) )
    
    
    
    #define W_PTR( var ) ( (word * ) (void * ) &(var) )
    
  6. 将一个字母转换为大写

    
    #define UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) )
    
  7. 防止溢出的一个方法

    
    #define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
    
  8. 返回数组元素的个数

    
    #define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
    
  9. 使用一些宏跟踪调试

ANSI标准说明了五个预定义的宏名。它们是:

__LINE__:在源代码中插入当前源代码行号;

__FILE__:在源文件中插入当前源文件名;

__DATE__:在源文件中插入当前的编译日期

__TIME__:在源文件中插入当前编译时间;

__STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;

__cplusplus:当编写C++程序时该标识符被定义

define中的三个特殊符号:##、#、#@

##: x连接y

#define Conn(x,y) x##y

#: 给x加上单引号,结果返回是一个const char

#define ToChar(x) #@x

#@:给x加上一个双引号

#define ToString(x) #x
2015-08-19 23:53:32 u011974126 阅读数 6638
  • 172集通俗易懂的C语言从入门到项目实战教程

    1) 本套课程针对高校大学生系统学习C语言而录制,从0基础入门讲起,循序渐进,通俗易懂,同时适用于计算机系及非计算机系的同学。通过学习可以帮助大家掌握C语言本质,轻松面对C语言全国二级考试,并达到能独立完成中型C项目、C游戏的水平; 2) 多数高校都开设了C语言课程,网上C语言课程也很多,但普遍存在两个问题: (1) 授课方式单一,大多是照着代码念一遍, 对刚刚接触编程的同学来说,感觉晦涩难懂 (2) 授课内容过度注重语法,没有项目实战支撑,造成课程枯燥无趣。本课程针对上述问题进行了改进 (1) 授课方式采用语法讲解+内存布局示意图+项目的方式,让课程生动有趣好理解 (2) 系统全面的讲解了C语言的核心技术点,还配套录制了《全国计算机二级C语言真题精讲》,让学员在掌握C语言编程的同时,还能轻松面对二级考试;3) 课程详细内容: 常量-变量、分支语句、循环语句、操作符和表达式、函数(库函数、自定义函数、递归调用 )、数组(一维数 组、二维数组、数组作为函数参数、指针数组)、指针(指针和指针类型、二级指针和多级指针、指针表达式解析、指针运算、数 组指针、函数指针、回调函数)、调试技巧、程序环境和预处理(翻译环境、运行环境、预定义符号、#define和#undef、宏和函 数、条件编译、文件包含)、 数据在内存中的存储、内存块分配、static、字符函数和字符串函数、自定义类型(结构体、枚举 、联合)、动态内存管理、文件操作(i/o常量、i/o函数、流)。

    73 人正在学习 去看看 张长志

研究生前两年做过不少项目,以前一直觉得自己水平还可以,然而今天去参加了腾讯的面试,问的问题都很基础,然而竟没有一个完完全全的回答上来,感觉自己好菜,唉,回来好好总结,为了offer继续努力。

C++中的宏有什么作用,由于在C#中取消了C++中的宏,那么C++中宏的那部分作用在C#中是如何实现的呢?

一、C++中宏的作用

1、使用宏定义常量

 示例:#define  MAXSIZE 200

宏定义不是C/C++严格意义上的语句,所以定义后不加分号,使用define后的标示符来代替常量,当我们需要在程序中多次使用200这个值,比如定义数组的长度等,并且可能在以后对该值做出修改时,

使用宏定义,我们仅需要改变宏定义所表示的值即可,而不需要到程序中去寻找哪些地方使用了200。

需要提到的是,在C++中 const也可以用来定义常量。那么const与宏定义的区别在哪儿呢?

(1)const定义常量是需要指出类型,而宏定义则不必:

#define  MAXSIZE 200 //宏定义;

const int MAXSIZE=200;//const定义;

两种方法可以实现相同的功能,即用MAXSIZE来代替常量200;

由于const在定义时需要指出类型,因此,

编译器会对const定义的常量进行静态类型安全检查,

而#define宏定义则是简单的替换,不会进行安全检查,并且可能会产生边界效应,

带来想不到的后果。

例如:#define N 100

#define M N+300

如果在程序中使用M*N,则结果会是100+300*100;

原因就在于定义M的时候是N+300而不是(M+300);

宏定义只是做简单的替换。

而const定义需要检查类型安全,如定义const float PI=3.141592653;

而实际得到的值却是PI=3.141593;这是由float的数据的长度所决定的。

(2)、当定义局部变量时,const所定义的变量的作用域,

仅限于const定义所在的函数段;

而使用宏定义#define,其作用域不仅限于定义所在的函数段,

而是从定义点到整个程序的结束。

(3)、const定义的常量在编译时会为该变量分配存储空间,而宏定义是在预编译时编译,

不分配存储空间(对于C语言,编译器会为const常量分配存储空间,但对于C++,

有些书上说编译器不会为const常量分配存储空间,而只是将其放在符号表中,

还有的说对于基本类型,不分配存储空间ADT等较大的对象要分配存储空间)

有些集成化的工具可以对const进行调试,但却不能对宏定义进行调试

(具体用什么工具,怎么调试我就不太清楚了)。


2、防止多重包含

预处理器变量:在编写头文件时,我们需要引入一些额外的预处理设置,

预处理器允许我们自定义变量。预处理器变量的名字在程序中必须是唯一的。

任何与预处理器变量相匹配的名字的使用都关联到该预处理器变量,而避免冲突,

预处理器变量一般使用大写的英文字符表示。预处理器变量有两种状态:

已定义和未定义。#define接收一个标识符,并定义该标识符为预处理器变量。

#ifndef检测指定的预处理器变量是否定义,如果未定义,则执行跟在其后的所有指令,

直到出现#endif。

在头文件的开头加上 如下代码

#ifndef  _HEAD_H_ //如果没有定义_HEAD_H_

#define _HEAD_H_//定义_HEAD_H_

然后在头文件的结束出加上#endif就可以避免该头文件被多次引用。


需要注意的是,防止头文件被重引用,还可以使用#pragma once来解决。

使用#pragma once 后,在编译时,编译器只对该文件编译一次;

与宏定义相比,#pragma once具有更快的速度和更高的效率,但是需要指出的是,

#pragma并不是所有的编译器都支持,可移植性较差。


有点晚了,明天继续...

2020-03-10 22:14:24 jinzhu1911 阅读数 32
  • 172集通俗易懂的C语言从入门到项目实战教程

    1) 本套课程针对高校大学生系统学习C语言而录制,从0基础入门讲起,循序渐进,通俗易懂,同时适用于计算机系及非计算机系的同学。通过学习可以帮助大家掌握C语言本质,轻松面对C语言全国二级考试,并达到能独立完成中型C项目、C游戏的水平; 2) 多数高校都开设了C语言课程,网上C语言课程也很多,但普遍存在两个问题: (1) 授课方式单一,大多是照着代码念一遍, 对刚刚接触编程的同学来说,感觉晦涩难懂 (2) 授课内容过度注重语法,没有项目实战支撑,造成课程枯燥无趣。本课程针对上述问题进行了改进 (1) 授课方式采用语法讲解+内存布局示意图+项目的方式,让课程生动有趣好理解 (2) 系统全面的讲解了C语言的核心技术点,还配套录制了《全国计算机二级C语言真题精讲》,让学员在掌握C语言编程的同时,还能轻松面对二级考试;3) 课程详细内容: 常量-变量、分支语句、循环语句、操作符和表达式、函数(库函数、自定义函数、递归调用 )、数组(一维数 组、二维数组、数组作为函数参数、指针数组)、指针(指针和指针类型、二级指针和多级指针、指针表达式解析、指针运算、数 组指针、函数指针、回调函数)、调试技巧、程序环境和预处理(翻译环境、运行环境、预定义符号、#define和#undef、宏和函 数、条件编译、文件包含)、 数据在内存中的存储、内存块分配、static、字符函数和字符串函数、自定义类型(结构体、枚举 、联合)、动态内存管理、文件操作(i/o常量、i/o函数、流)。

    73 人正在学习 去看看 张长志

在宏定义中经常看到符号###的使用,该篇博客就结合宏定义的展开方式说明这两种符号的具体作用。
本文参考学习该篇博客:参考来源——#和##的用法

用法说明

#define f(a,b) a##b      //     (1)
#define g(a)   #a        //     (2) 
#define h(a)   g(a)      //     (3)  

在上述三个宏定义中使用了符号###,使用上述宏如下代码所示

printf("%s\n", g(f(1, 2)));
printf("%s\n", h(f(1, 2)));

输出以下结果:
f(1, 2)
12

根据以上代码的输出结果,可以总结出###的用法:

符号#表示“字符串化”的意思,就是把跟在后面的参数转换成一个字符串,例如上述代码中g(f(1, 2))输出的结果为f(1, 2)
符号##是一个连接符号,用于把参数连在一起,例如a##b等同于ab

但是大家一定对于上述代码中第二输出感觉到很疑惑,想当然认为输出结果为f(1, 2),这里就需要注意以下两点:

 如果宏定义是带#的,如(2)所示,则直接替换。g(f(1,2))--->#f(1,2)--->"f(1,2)"
 如果宏定义是不带#的,如(1)、(3)所示,基本原则为展开参数然后替换。   
	步骤为:由外层向里层走,如果碰到的是以非#开头的宏,则继续往里层走,直到最里层,然后开始往外层展开。  
	如果碰到的是以#开头的宏,则不再往里层走,往外层展开。h(f(1,2))--->h(12)--->g(12)--->#12--->"12"

下面再举一些例子,大家可以在每行代码的后面看到具体的输出结果:

char a = 'c';
cout << g(a) << endl; // "a"
cout << g(g(a)) << endl; // "g(a)"
printf("%s\n", h(f(1, 2)));   // "12"
printf("%s\n", g(f(1, 2))); // "f(1,2)"
printf("%s\n", g(h(f(1, 2)))); // "h(f(1,2))"
printf("%s\n", h(g(f(1, 2)))); // ""f(1,2)""
printf("%s\n", h(h(f(1, 2)))); // ""12""
2016-11-10 10:56:28 guyuealian 阅读数 1131
  • 172集通俗易懂的C语言从入门到项目实战教程

    1) 本套课程针对高校大学生系统学习C语言而录制,从0基础入门讲起,循序渐进,通俗易懂,同时适用于计算机系及非计算机系的同学。通过学习可以帮助大家掌握C语言本质,轻松面对C语言全国二级考试,并达到能独立完成中型C项目、C游戏的水平; 2) 多数高校都开设了C语言课程,网上C语言课程也很多,但普遍存在两个问题: (1) 授课方式单一,大多是照着代码念一遍, 对刚刚接触编程的同学来说,感觉晦涩难懂 (2) 授课内容过度注重语法,没有项目实战支撑,造成课程枯燥无趣。本课程针对上述问题进行了改进 (1) 授课方式采用语法讲解+内存布局示意图+项目的方式,让课程生动有趣好理解 (2) 系统全面的讲解了C语言的核心技术点,还配套录制了《全国计算机二级C语言真题精讲》,让学员在掌握C语言编程的同时,还能轻松面对二级考试;3) 课程详细内容: 常量-变量、分支语句、循环语句、操作符和表达式、函数(库函数、自定义函数、递归调用 )、数组(一维数 组、二维数组、数组作为函数参数、指针数组)、指针(指针和指针类型、二级指针和多级指针、指针表达式解析、指针运算、数 组指针、函数指针、回调函数)、调试技巧、程序环境和预处理(翻译环境、运行环境、预定义符号、#define和#undef、宏和函 数、条件编译、文件包含)、 数据在内存中的存储、内存块分配、static、字符函数和字符串函数、自定义类型(结构体、枚举 、联合)、动态内存管理、文件操作(i/o常量、i/o函数、流)。

    73 人正在学习 去看看 张长志

C/C++语言宏定义##连接符和符#的使用 

    【尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/53113187
(一)C/C++语言宏定义##连接符和符#的使用
   (1) ## 连接符:在带参数的宏定义中, 用来将两个Token连接为一个Token,从而形成一个新的子串。注意这里连接的对象是Token就行,而不一定是宏的变量。
    例子:
#define XNAME(n) x ## n  
    当出现int XNAME(1) = 14;时,会被替换为:
int x1=14;
     (2)#符:是将其后面的宏参数进行字符串化操作(Stringfication),即把宏参数变为一个字符串,简单说就是在对它所引用的宏变量 通过替换后在其左右各加上一个双引号。#符,也就是把传递过来的参数当成字符串进行替代。
    例子:
#define WARN_IF(EXP) do{ if (EXP) fprintf(stderr, "Warning: " #EXP "/n"); } while(0)
当出现WARN_IF (divider == 0);时,相当于如下替换:
do {
	if (divider == 0)
		fprintf(stderr, "Warning" "divider == 0" "/n");
} while(0);
    可见#EXP将会被替换为【“divider == 0"】

C/C++宏定义中的#

阅读数 442

没有更多推荐了,返回首页