关闭

C语言开发总结(一)

153人阅读 评论(0) 收藏 举报
分类:

1.1 c++中的 -> 、::、 .的作用,都分别用在什么地方

->是指针,是一个指针变量访问其所指向地址存放其内部成员的方式;如struct A{int a;int b;}tmp;
struct A *p = new struct A; cout<<p->a<<p->b;其使用是和.类似,不同的是因为其是指针的缘故
::是作用域符号,主要有3个作用
1:作用域符号::的前面一般是类名称,后面一般是该类的成员名称,C++为例避免不同的类有名称相同的成员而采用作用域的方式进行区分
如:A,B表示两个类,在A,B中都有成员member。那么
A::member就表示类A中的成员member
B::member就表示类B中的成员member 
2:全局作用域符号:当全局变量在局部函数中与其中某个变量重名,那么就可以用::来区分如:
char zhou; //全局变量
void sleep()

char zhou; //局部变量
char(局部变量) = char(局部变量) *char(局部变量) ; 
::char(全局变量) =::char(全局变量) *char(局部变量); 

3:::是C++里的“作用域分解运算符”。比如声明了一个类A,类A里声明了一个成员函数voidf(),但没有在类的声明里给出f的定义,那么在类外定义f时,就要写成voidA::f(),表示这个f()函数是类A的成员函数。
.是用来访问类,结构等内部成员的运算符,是同->相同的使用方式

::是C++里的“作用域分解运算符”。比如声明了一个类A,类A里声明了一个成员函数voidf(),但没有在类的声明里给出f的定义,那么在类外定义f时,就要写成voidA::f(),表示这个f()函数是类A的成员函数。例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CA {
public:
  int ca_var;
  int add(int a, int b);
  int add(int a);
};
 
//那么在实现这个函数时,必须这样书写:
int CA::add(int a, int b)
{
  return a + b;
}
 
//另外,双冒号也常常用于在类变量内部作为当前类实例的元素进行表示,比如:
int CA::add(int a)
{
  return a + ::ca_var;
}
 
//表示当前类实例中的变量ca_var。

第一个是指针 第二个是作用域 第三个 是类成员使用
比如: 
struct string 

char name[8]; 
char sex[4]; 
int age; 
char addr[40]; 

struct string *student; 
student->age = 18;/*给数组中age 赋值。 
借用下*/
student->age = 18;//也可以这样*student.age = 18;
相当於".成员"的作用,但定义成指针时则用"->成员"
struct a
{
int num
int age
}
a b;
a * c;
b.num
c->num
这样好懂了吧.

1.2  C语言 字符串前加L的意义 如:L“A”
Unicode或者宽字符都没有改变char数据型态在C中的含义。char继续表示1个字节的储存空间,sizeof (char)继续返回1。理论上,C中1个字节可比8位长,但对我们大多数人来说,1个字节(也就是1个char)是8位宽。
C中的宽字符基于wchar_t数据型态,它在几个表头文件包括WCHAR.H中都有定义,像这样:
typedef unsigned short wchar_t ;
因此,wchar_t数据型态与无符号短整数型态相同,都是16位宽。
要定义包含一个宽字符的变量,可使用下面的语句:
wchar_t c = 'A' ;  
变量c是一个双字节值0x0041,是Unicode表示的字母A。(然而,因为Intel微处理器从最小的字节开始储存多字节数值,该字节实际上是以0x41、0x00的顺序保存在内存中。如果检查Unicode文字的计算机储存应注意这一点。)
您还可定义指向宽字符串的指针:
wchar_t * p = L"Hello!" ;
注意紧接在第一个引号前面的大写字母L(代表「long」)。这将告诉编译器该字符串按宽字符保存-即每个字符占用2个字节。通常,指针变量p要占用4个字节,而字符串变量需要14个字节-每个字符需要2个字节,末尾的0还需要2个字节。
同样,您还可以用下面的语句定义宽字符数组:
static wchar_t a[] = L"Hello!" ;
该字符串也需要14个字节的储存空间,sizeof (a) 将返回14。索引数组a可得到单独的字符。a[1] 的值是宽字符「e」,或者0x0065。
虽然看上去更像一个印刷符号,但第一个引号前面的L非常重要,并且在两个符号之间必须没有空格。只有带有L,编译器才知道您需要将字符串存为每个字符2字节。稍后,当我们看到使用宽字符串而不是变量定义时,您还会遇到第一个引号前面的L。幸运的是,如果忘记了包含L,C编译器通常会给提出警告或错误信息。
您还可在单个字符文字前面使用L前缀,来表示它们应解释为宽字符。如下所示:
wchar_t c = L'A' ;
但通常这是不必要的,C编译器会对该字符进行扩充,使它成为宽字符。

1.3 ##、#、#@在C中的作用(VC)

先来段程序:

  1. #include <stdio.h>

  2. #define f(a,b) a##b

  3. #define g(a)   #a

  4. #define h(a)   g(a)

  5. #define p(a)   #@a

  6. int main(int argc, char* argv[])

  7. {

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

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

  10.    printf("%c, %d\n", p(1), p(1));

  11. return 0;

  12. }

输出结果

看上去有点奇怪。

##是连接操作符(我也不知道中文是啥,google到的是token-pasting operator),可以将操作符两端的标识符级联起来。

#是字符串化操作符(stringizing operator),可以将操作符后的标识符转化成字符串。

#@是字符化操作符(charizing),可以将操作符后的数据转化成字符。

来分析程序。

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

g(f(1,2)),即#f(1,2),被转化成了字符串,于是g(f(1,2))就变成了"f(1,2)"。

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

h(f(1,2)),这里需要注意一下,#跟##不一样,如果宏定义的替换部分恰好跟其他的宏定义名字一样的话,会进行展开,即调用h(a)会先对g(a)进行展开。详见http://c-faq.com/ansi/stringize.html。如此一来,h(f(1,2))会先对f(1,2)进行运算,变成12,再运行h(12),变成"12"。

  1. printf("%c, %d\n", p(1), p(1));  

p(1),1被转化成字符,为了验证,输出它的ASCII码。

#,##, #@都仅适用于宏定义,在程序中无法单独使用。

有一道经典的C语言问题,关于宏定义中#和##符号的使用和宏定义展开问题
 
程序如下:

#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)));
        printf("%s\n", g(f(1,2)));
        return 0;
}

答案:第一行:12  第二行:f(1,2)

说明:

1、关于符号#和##

两个符号都只能用于预处理宏扩展。不能在普通的源码中使用它们,只能在宏定义中使用。

简单的说,#是把宏参数变为一个字符串,##是把两个宏参数连接在一起。

关于这两个符号的具体意义和用法可以参见两篇文章:

#和##在宏替换中的作用 http://www.linuxidc.com/Linux/2014-06/102921.htm

C/C++ 宏中"#"和"##"的用法 http://www.linuxidc.com/Linux/2014-06/102924.htm

还有GCC帮助文档上的解释:

3.4 Stringification

3.5 Concatenation

2、关于宏展开

预处理过程的几个步骤:

1)字符集转换(如三联字符)

2)断行链接/

3)注释处理,/* comment */,被替换成空格

4)执行预处理命令,如#inlcude、#define、#pragma、#error等

5)转义字符替换

6)相邻字符串拼接

7)将预处理记号替换为词法记号

第4)步即如何展开宏函数的规则:在展开当前宏函数时,如果形参有#或##则不进行宏参数的展开,否则先展开宏参数,再展开当前宏。

宏替换顺序英文描述如下:

A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token, is replaced by the corresponding argument after all macros contained therein have been expanded.

3、总结

综合以上,对于这道题来说,第一行h(f(1,2)),由于h(a)非#或者##所以先展开其参数f(1,2),即12,所以变成h(12),然后再宏替换为g(12),再次替换为12。

第二行g(f(1,2)),宏g(a)带有#,所以里面的f(1,2)不展开,所以变成f(1,2)

类似的这种问题在《你必须知道的495个C语言问题》中出现过,在121页的“预处理功能”的问题11.19,有兴趣的朋友可以看一看。

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码 http://www.linuxidc.com/Linux/2014-05/101227.htm

读C++ Primer 之构造函数陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

读C++ Primer 之智能指针 http://www.linuxidc.com/Linux/2011-08/40177.htm

读C++ Primer 之句柄类 http://www.linuxidc.com/Linux/2011-08/40175.htm

C++11 获取系统时间库函数 time since epoch http://www.linuxidc.com/Linux/2014-03/97446.htm

C++11中正则表达式测试 http://www.linuxidc.com/Linux/2012-08/69086.htm

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:321590次
    • 积分:9146
    • 等级:
    • 排名:第2086名
    • 原创:638篇
    • 转载:46篇
    • 译文:2篇
    • 评论:12条
    最新评论