zoukankan      html  css  js  c++  java
  • c++随笔1

    C语言和C++都有一个专为调试而准备的工具函数,就是 assert()函数

    这个函数是在C语言的 assert.h 库文件里定义的,

    所以包含到C++程序里我们用以下语句:#include <cassert>

    作用是,如果它的条件返回错我,则终止程序的执行。

    区分char *和char []:char *定义的是一个指向字符串的指针(注意:C语言中没有对应字符串的内置类型或者类类型),而char []就是C语言中的用来定义字符数组(注意:字符数组是不同于字符串,如果字符数组以''结尾,那么可以视为字符串)。

    char a[]在运行时赋值,值会从静态区赋值到函数的栈中,对它进行修改不会产生任何问题。char *a在编译时就确定了,a指向静态区中的值,没有赋值到函数栈中, 因此对指针的内容进行修改会产生错误

    了解一下 一个由 C / C++ 编译的程序占用的内存分为以下几个部分: 
    1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
    2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由 OS 回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
    3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后由系统释放 。
    4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
    5、程序代码区—存放函数体的二进制代码。

    关于头文件和源文件的分别

    首先,我们可以将所有东西都放在一个.cpp文件内.

    然后编译器就将这个.cpp编译成.obj,obj是什么东西?

    就是编译单元了.一个程序,可以由一个编译单元组成,

    也可以有多个编译单元组成. 如果你不想让你的源代码变得很难阅读的话,

    就请使用多个编译单元吧.(一个函数不能放到两个编译单元里面,但两个以上

    就可以分别放在一个单元,也就是cpp里面)

        那么就是一个.cpp对应一个.obj,然后将所有的obj链接起来(通过一个叫链接器的程序),

    组成一个.exe,也就是程序了.

        如果一个.cpp要用到另一个.cpp定义的函数怎么办? 只需在这个.cpp种写上他的函数声明

    就可以了.其余工作由链接器帮你完成,你可以随便调用该函数.

        链接器将所有的obj连接起来,但是如果碰巧有相同的函数或外部变量怎么办?他如何识别?

    一般来说是不能允许在同一个程序中,出现两个一样的函数名或外部变量名.

        但是只得庆幸的是,c++可以通过一种叫做链接属性的关键字来限定,你这个函数是属于整个程序

    公用的,还是只是在一个编译单元obj里面使用的.

        这些关键字就是extern 和 static extern是外部链接的意思,也就是除了这个单元,外部的单元也是能够访问这个函数的.static 是内部链接,自属于自己单元.

    说了这么久,还没有说.h的作用呢?

        其实没有.h也能很好的工作,但是当你发现一个外部链接的函数或外部变量,需要许多份

    声明,因为c++这种语言,在使用函数和变量的时候,必须将他声明,为何要声明?声明之后才

    知道他的规格,才能更好的发现不和规格的部分.你别妄想一个编译单元,会自动从另一个

    编译单元那里得到什么信息,知道你是如何定义这个函数的.

        所以说,只要使用到该函数的单元,就必须写一份声明在那个.cpp里面,这样是不是很麻烦,

    而且,如果要修改,就必须一个一个修改.这真让人受不了.


    .h就是为了解决这个问题而诞生,他包含了这些公共的东西.然后所有需要使用该函数的.cpp,只需要

    用#include包含进去便可.以后需要修改,也只是修改一份内容.


    请注意不要滥用.h,.h里面不要写代码,.h不是.cpp的仓库,什么都塞到里面.

    如果在里面写代码,当其他.cpp包含他的时候,就会出现重复定义的情况,

    比如将函数func(){printf};放到头文件a.h,里面还有一些a.cpp需要的声明等;

    然后你发现b.cpp需要用到a.cpp里面的一个函数,就很高兴的将a.h包含进来.

    注意,#include并不是什么申请指令,他就是将指定的文件的内容,原封不动的拷贝

    进来.


    这时候实际上a.cpp和b.cpp都有一个func()函数的定义.

    如果这个函数是内部链接static的话,还好,浪费了一倍空间;

    如果是extern,外部链接(这个是默认情况),那么根据在同一个程序内不可出现

    同名函数的要求,连接器会毫不留情给你一个连接错误!

    为了避免同一个文件被include多次

    1   #ifndef方式
    2   #pragma once方式

    在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。
        方式一:

        #ifndef __SOMEFILE_H__
        #define __SOMEFILE_H__
        ... ... // 一些声明语句
        #endif

        方式二:

        #pragma once
        ... ... // 一些声明语句


        #ifndef的方式依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心“撞车”,可能就会导致头文件明明存在,编译器却硬说找不到声明的状况

        #pragma once则由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,重复包含更容易被发现并修正。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main()
     4 {
     5     printf("The program test print style!
    ");
     6     /* 以十进制形式输出带符号整数(正数不输出符号) */
     7     printf("%d
    ", 223);
     8     printf("%d
    ", -232);
     9     printf("
    ");
    10     /* 以八进制形式输出无符号整数(不输出前缀O) */
    11     printf("%o
    ", 223);
    12     printf("%o
    ", -232);
    13     printf("
    ");
    14     /* 以十六进制形式输出无符号整数(不输出前缀OX) */
    15     printf("%x
    ", 223);
    16     printf("%x
    ", -232);
    17     printf("
    ");
    18     /* 以十进制形式输出无符号整数 */
    19     printf("%u
    ", 223);
    20     printf("%u
    ", -232);
    21     printf("
    ");
    22     /* 以小数形式输出单、双精度实数 */
    23     printf("%f
    ", 223.11);
    24     printf("%f
    ", 232.11111111);
    25     printf("%f
    ", -223.11);
    26     printf("%f
    ", -232.11111111);
    27     printf("
    ");
    28     /* 以指数形式输出单、双精度实数 */
    29     printf("%e
    ", 223.11);
    30     printf("%e
    ", 232.11111111);
    31     printf("%e
    ", -223.11);
    32     printf("%e
    ", -232.11111111);
    33     printf("
    ");
    34     /* 以%f%e中较短的输出宽度输出单、双精度实数 */
    35     printf("%g
    ", 223.11);
    36     printf("%g
    ", 232.111111111111);
    37     printf("%g
    ", -223.11);
    38     printf("%g
    ", -232.111111111111);
    39     printf("
    ");
    40     /* 输出单个字符 */
    41     printf("%c
    ", 'a');
    42     printf("%c
    ", 97);   //输出为  'a'
    43     printf("
    ");
    44     /* 输出单个字符 */
    45     printf("%s
    ", "this is a test!");
    46     printf("%s
    ", "2342o34uo23u");
    47     printf("
    ");
    48     getch();
    49 }

    assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行

    C编译器要求变量的声明需要放在作用域的开头,这里是函数的开始处。而C++编译器不要求在哪用就在哪声明,也可以在开头声明好。所以,写C++代码是就比较放得开,什么时候需要什么时候声明就可以了。

    sizeof(数组名)计算数组大小并不是每次都管用哦。sizeof(数组名)/sizeof(数组一个元素)也并不是每次都可以正确计算数组元素个数哦。

    强行记忆学不好编程

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main()
     4 {
     5     char url[] = "www.baidu.com";
     6     char bb[] = { 0,1,2,3,4 };
     7     int age[]= { 0,1,2,3,4 };
     8     int isizeurl = sizeof(url);
     9     int isizebb = sizeof(bb);
    10     int isizeage = sizeof(age);
    11     printf("isizeurl:%d
    ", isizeurl);
    12     printf("isizebb:%d
    ", isizebb);
    13     printf("isizeage:%d", isizeage);
    14     getchar();
    15 }

    你可以看到,sizeof(数组名)是可以计算得到数组的字节大小的。这并不是全部的事实!

    Linux系统下C程序开发详解:

    1 .ii为扩展名的文件,是已经预处理过的C++源代码文件,也是中间代码文件。 

    2  .o为扩展名的文件,是编译后的目标文件,源文件生成的中间目标文件。

    3 .s为扩展名的文件,是汇编语言源代码文件。 

    4 .S为扩展名的文件,是经过预编译的汇编语言源代码文件。 

    5 .o为扩展名的文件,是编译以后的程序目标文件(Object file),目标文件经过连接成可执行文件

    注意 NULL 就是 NULL,它被宏定义为 0

      #define NULL 0

     很多系统下除了有 NULL 外,还有 NUL

    NUL 是 ASCII 码表的第一个字符,表示的是空字符,其 ASCII 码值为 0。其值虽然都为 0,但表示的意思 完全不一样。

    函数宏中的#和##运算符

    在函数宏中#可以实现由函数宏实参生成字符串常量##实现了由函数宏实参生成标识符的一部分。(前者用于拼接字符串后者用于拼接标示符)看一下下边的示例:

    假如希望在字符串中包含宏参数,ANSI C允许这样作,在类函数宏的替换部分,#符号用作一个预处理运算符,它可以把语言符号转化程字符串。例如,如果x是一个宏参量,那么#x可以把参数名转化成相应的字符串。该过程称为字符串化

    1 #include<stdlib.h>
    2 #include<stdio.h>
    3 #define psqs(x) printf("the square of"#x "is %d.
    ",(x)*(x))
    4 int main(void) {
    5     int y = 4;
    6     psqs(y);
    7     psqs(2 + 4);
    8     system("pause");
    9 }

    第一次调用宏时使用“y”代替#x;第二次调用时用“2+4″代#x。

    ##运算符可以使用类函数宏的替换部分。另外,##还可以用于类对象宏的替换部分。这个运算符把两个语言符号组合成单个语言符号。例如:

    #define XNAME(n) x##n

    这样宏调用:

    XNAME(4)

    展开后:x4

    Coding
  • 相关阅读:
    Debug与Trace的区别?//作者:西西
    C#中substring ()的用法 //作者:张亚涛
    C# Lambda表达式 //作者:Kingmoon
    软件测试工具有哪些?软件测试工具下载?--最全最新的官网下载地址都在这里!错过绝对后悔!
    全网最全最细的appium自动化测试环境搭建教程以及appium工作原理
    手机app测试用例怎么写?手机app测试点有哪些?只有干货没有水分,错过绝对后悔!
    全网最全最细的jmeter接口测试教程以及接口测试流程详解
    全网最全最细的fiddler使用教程以及工作原理
    自学软件测试的网站有哪些?一个10年测试老鸟的珍藏!吐血推荐!
    软件测试工程师应该被尊重--让我们为测试正名!
  • 原文地址:https://www.cnblogs.com/ccie-leon-43093/p/5513300.html
Copyright © 2011-2022 走看看