回味C语言

2023-10-31

虽然在实际上没怎么使用C语言了,但是看到C语言的书总是忍不住想看一下(喜欢这种至简,却又有着强大能力的语言),读完书随手写的一些笔记,略有些简单。书还是很喜欢的,推荐给大家(C专家编程)

第一章 C:穿越时空的迷雾


  • 原型决定C语言不支持函数重载
//previous definition is here
void overload(int a)
{
    printf("%d\n",a);
}

void overload(double a)
{
    printf("%lf\n",a);
}
  • 参数传递类似于赋值
void assign(char a)
{
    printf("%d\n",a);
}
//指针类型才会出现这种错误
void assignpoint(char *p)
{
    printf("%s\n",p);
}
//gcc C++ error C warning
int main()
{
    const char a = 5;
    assign(a);
    const char *p = "helloworld";
    //argument is incompatible with prototype
    assignpoint(p);
}  
  • 尽量不要使用无符号类型
int array[5] = {1,2,3,4,5};
//当数组类型发生变化时,这种方式比下面的方法更通用
#define TOTAL_ELEMENTS sizeof(array)/sizeof(array[0])
// #define TOTAL_ELEMENTS sizeof(array)/sizeof(int)

int main()
{
    int d = -1;
    // TOTAL_ELEMENTS类型是无符号整数,d被转化为无符号数
    // 需要强制类型转化
    // if(d<(int)TOTAL_ELEMENTS)
    if(d<TOTAL_ELEMENTS)
    {
        printf("hello");
    }
}  

第二章 这不是Bug,而是语言特性

书中的这句话成了现在的经典啊
this is not a bug,it’s a feature

  • switch
#include<stdio.h>
int main()  
{
    const int two = 2; //现在编译器不会出现错误
    //case条件不能是变量,只能是整形常量包括char, short, int, long
    int i=2;
    //一条switch语句最多257个case标签
    //8bit的所有情况加上EOF
    switch(i)
    {
        //没有break则顺序执行,不执行default
        case 1:printf("case 1\n");
        //default 打错了也能编译通过
        defult:printf("default"); //default 顺序不影响
        case two:printf("case 2\n");
        case 3:printf("case 3\n");
    }
}
  • 字符串自动连接
#include<stdio.h>
int main()  
{
    //加斜杠空格,第二行前面的空格也算在内,没有反斜杠会报错
    printf("a favorite children's book\
    is muffy\n");
    //新风格字符串自动连接
    printf("a favorite children's book"
    " is muffy\n");
    //定义数组时要注意
    char *strs[] = {"red""green","yellow"};
    printf("%s\n",strs[0]);
}
  • 符号重载
#include<stdio.h>
int main()
{
    int *p;
    int i=3,apple;
    p=&i;
    // invalid operands to binary expression ('unsigned long' and 'int *')
    apple = sizeof(int)*p;
}
  • 运算符优先级
优先级 表达式 实际结果
.的优先级高于* *p.f *(p.f)
[]高于* int *ap[] int *(ap[])
函数()高于* int *fp() int *(fp())
==和!=高于位操作符 val&mask!=0 val&(mask!=0)
==和!=高于赋值符 c=getchar()!=EOF c=(getchar()!=EOF)
算数运算符高于移位运算符 msb<<4+lsb msb<<(4+lsb)
逗号运算符最低 i=1,2 (i=1),2

* 最大一口策略

int main()
{
    int x=2,y=3,temp;
    temp = y+++x;
    printf("%d\n",temp);
    // temp = y+++++x; //缺少空格
    // temp = y++ ++ +x; //不能编译通过
    printf("%d\n",temp);
}
  • lint程序

第三章 分析C语言的声明

C语言的声明是被玩坏了的,还是希望简单点的好。
不过偶尔烧脑,也不失为一个明智的决策

  • 声明复杂性

    1. 函数的返回值不能是一个函数,foo()()是非法的
    2. 函数的返回值不能是一个数组,foo()[]是非法的
    3. 数组里面不能有函数,foo是非法的

下面是合法的 * 函数的返回值允许是一个函数指针,如int(* fun())(); * 函数的返回值允许是一个指向数组的指针,如int(fun())[]; 数组里面允许有函数指针,如int(fun[])() 数组里面允许有其他数组int foo[][]

  • 位段,无名字段和填充字段
#include<stdio.h>
int main()
{
    struct dog
    {
        char id;
        short height;
        int weight;
    };
    //字节对齐
    printf("%lu\n",sizeof(struct dog));//8
    //位填充不影响字节对齐
    struct pid_tag
    {
        unsigned int inactive : 1;
        unsigned int :1; //1个位填充
        unsigned int refcount : 6;
        unsigned int :0; //填充到下一个字边界
        short pid_id;
        short :0;
        struct pid_tag *link;
    };
    printf("%lu\n",sizeof(struct pid_tag));//16
}
  • typedef 和 #define
#include<stdio.h>
int main()
{
    #define peach int  //没有分号
    unsigned peach i;  //incorrect

    typedef int banans;
    // unsigned banans i; //incorrect

    #define int_ptr int *
    int_ptr chalk,cheese;  //chalk是指针,cheese是int

    typedef char * char_ptr;
    char_ptr Bentley,Rolls_Royce; //两个char*
}

第四章 令人震惊的事实:数组和指针并不相同

  • 左值和右值

左值是地址,而右值是地址的内容

声明为指针,定义为数组 会出错
原因如下
char a[9] = “abcdefgh” c = a[i]
编译器符号表示具有一个地址9980
运行时步骤1: 取i的值,将它与9980相加
运行时步骤2: 取地址(9980+i)的内容

char *p = “abcdefgh” c = p[i]
编译器符号表示具有一个p地址4624
运行时步骤1: 取地址4624的内容9980
运行时步骤2: 取i的值,将它与9980相加
运行时步骤3: 取地址(9980+i)的内容

通过上述两步,即可理解当声明为指针,定义为数组时会出错
首先当p声明为指针时,会依照三步来获取内容,错误出现在步骤1
需要对数组名取内容,实际是数组第一个元素的值,加上偏移量
得到错误的结果

第五章 对链接的思考

  • 链接库

使用vc编译器
cl –c cppfile 生成obj文件
静态链接库
lib objfile 生成lib文件
动态连接库
__declspec(dllexport) //必须添加,导出函数,这样就会有lib文件生成
link /dll objfile 生成dll文件
查看动态链接库 dumpbin /exports dllfile

windows下调用动态链接库

#include<iostream>
#include<windows.h>
using namespace std;

// windows 下的调用方式
int main()
{
    typedef void (*pfunc)(void);
    HINSTANCE hDll=LoadLibrary("E:\\CClearning\\DynamicLinkLibrary\\dll.dll");
    if(!hDll)
    {
        cout<<"LoadLibrary Error: "<<GetLastError()<<endl;
        return 0;
    }
    cout<<"dll.dll的句柄地址:"<< hDll << endl;

    //pfunc本身表示指针,不能再用pfunc*
    //pfunc * pf=(pfunc *)GetProcAddress(hDll,"?greet@@YAXXZ");

    pfunc pf=(pfunc)GetProcAddress(hDll,"?greet@@YAXXZ");
    if(!pf)
    {
        cout<<"GetProcAddress Error: "<<GetLastError()<<endl;
        return 0;
    }
    cout<<"dll.dll内的greet()函数的地址:"<< pf <<endl;

    pf();
    //(*pf)();
    //使用完毕后,释放dll文件
    FreeLibrary(hDll);
}

使用gcc编译器
g++ -c cppfile 生成.o链接文件
静态连接库 ar rc liblib.a lib.o 生成.a静态文件
要指定生成文件名liblib.a
然后链接静态库
g++ gccstatic.cpp -L . -l lib
L指定要搜索的库的路径,l指定要搜索的库的名字,可以省略libXXX.a
当然MinGW可以使用这种方法g++ gccstatic.cpp liblib.a

动态连接库
g++ dll.cpp -shared -o libdll.so 生成.so动态链接文件
然后链接动态库
g++ gccdynamic.cpp libdll.so

第六章 运行时数据结构

  • a.out中各个段,数据段,代码段

  • setjmp可以实现异常处理

#include<stdio.h>
#include<setjmp.h>

jmp_buf buf;

// warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
banana()
{
    printf("in banana() \n");
    longjmp(buf,1);
    //一下代码不会被执行
    printf("you'll never see this,because i longjmp'd");
}

main()
{
    if(setjmp(buf))
    {
        printf("back in main\n");
    }
    else
    {
        printf("first time through\n");
        banana();
    }
}

第七章 对内存的思考

内存中的分段和分页

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

回味C语言 的相关文章

随机推荐

  • R中使用foreach时清理内存

    foreach能较大的提高计算速度 但是R不会自动清理内存 导致服务器内存经常占用过高 因此使用时需要及时清理内存 以如下例子所示 我需要读取一批excel文件 在运行下面的代码前 经过4次测试 Rstudio的内存情况是这样的 Mb 23
  • VMware安装虚拟机(小白看了都会哦)

    一 什么是VMware VMware是一款运行在windows系统上的虚拟机软件 可以虚拟出一台计算机硬件 方便安装各类操作系统 如Windows Macos Linux Unix等等 虚拟机 VM 是一种创建于物理硬件系统 位于外部或内部
  • 质疑百度的“国学”

    2006年11月03日 18 07 00 百度 这个名字取得非常好 他有一个广告 也不错 这些无不在向人们展示 汉语 的魅力和中国文化的底蕴 才可能构成今日 世界有Google 中国有百度 的格局 但是从百度其中一个产品 国学 来看 百度做
  • 反射、线程

    反射 如何在程序运行的情况下去创建另外一个对象 JAVA反射机制是在运行状态中 对于任意一个类 都能够知道这个类的所有属性和方法 对于任意一个对象 都能够调用它的任意一个方法和属性 这种动态获取的信息以及动态调用对象的方法的功能称为java
  • CNN浅析和历年ImageNet冠军模型解析

    版权声明 作者 黄文坚 本文为大数据杂谈4月13日微信社群分享内容整理 最新人工智能论文 http paperreading club 今天在这里我给大家讲解一些深度学习中卷积神经网络的原理和一些经典的网络结构 卷积神经网络原理浅析 卷积神
  • 苹果系统版本依次顺序_iphone所有型号上市顺序

    Ready 本期给大家讲讲iphone所有型号上市顺序 第一代iPhone于2007年1月9日由苹果公司前首席执行官史蒂夫 乔布斯发布 并在2007年6月29日正式发售 第二代iPhone 3G于2008年6月10日由美国苹果公司的掌门人史
  • 【Linux之shell脚本实战】统计 Linux 进程相关数量信息

    Linux之shell脚本实战 统计 Linux 进程相关数量信息 一 脚本要求 二 检查本地服务器状态 1 检查系统版本 2 检查系统内核版本 三 配置脚本注释模板 1 编辑 vimrc 文件 2 检查模板生效情况 四 编写ps aa s
  • 0基础速通MySql基础

    一 基本配置 经过一系列配置后 可以与客户端进行连接 二 基本操作 数据模型 1 关系型数据库 RDBMS 概念 建立在关系模型基础上 由多张相互连接的二维表组成的数据库 2 数据模型 MySQL是关系型数据库 是基于二维表进行数据存储的
  • 正点原子阿波罗STM32F429开发板资料发布,采用底板+核心板

    正点原子阿波罗STM32F429开发板资料发布 采用底板 核心板 https www amobbs com thread 5654611 1 1 html 正点原子STM32开发板 http www openedv com docs boa
  • IP addr添加网络的使用

    IP addr 添加网络的使用 添加IP到网口 root localhost ip addr add 192 168 10 100 24 dev em1 查看添加的IP root localhost ip addr show 移除添加的IP
  • 卸载或重新安装JDK出现"Windows Installer程序包有问题,此安装需要的DLL不能运行"解决方法(转)

    首先确保windows installer服务是开启的 运行services msc 看看windows installer服务是否启动 先启动看看能否解决 当然本人的是一直启动着的但还是卸载不了 想办法去删注册表却删不全 总是没法解决 之
  • 期货反向跟单的四大跟单禁忌

    对于在反向跟单路上的朋友 经典的 二八定律 这么完美 它依然坚不可摧 但是跟单落地的结果却不一定能成功 反向跟单经验已经做过多次介绍 不过成功各有不同 但是误区无非就以上几个 1忌 不加筛选 盲目乱跟 跟单的样本数据 必须经过筛选 不能不管
  • Arthas & GC日志-JVM(十八)

    上篇文章说jvm的实际运行情况 Jvm实际运行情况 JVM 十七 Arthas介绍 因为arthas完全是java代码写的 我们直接用命令启动 Java jar arthas boot jar 启动成功后 选择我们项目的进程 进入我们可用d
  • Uniapp学习之从零开始写一个简单的小程序demo(新建页面,通过导航切换页面,发送请求)

    先把官网文档摆在这 后面会用到的 uniapp官网文档 https uniapp dcloud net cn vernacular html 一 开发工具准备 1 1 安装HBuilder 按照官方推荐 先装一个HBuilder 下载地址
  • 修复maven缓存导致Jenkins打包失败

    问题 笔者近期在公司搭建了一个内网的nexus 所以每次有新项目要部署到Jenkins时需要使用脚本将相关依赖导入到nexus上 近期笔者在Jenkins配置了一个item报错 然后将相关依赖导入nexus中 再次打包时出现下面这段异常 笔
  • 【VUE】在vue项目实践当中使用swiper轮播图教程

    步骤 1 安装vue awesome swiper npm install vue awesome swiper S 2 在vue项目中引用vue awesome swiper main js import VueAwesomeSwiper
  • Java是面向过程语言还是面向对象语言?

    目录 一 面向过程语言 二 面向对象语言 三 Java是面向过程语言还是面向对象语言 一 面向过程语言 面向过程语言是一种编程范式 它将程序设计看作是按照一定的步骤或流程进行处理的过程 在面向过程语言中 程序员需要自己定义数据结构和算法 并
  • linux的链接方式

    linux的硬链接和软链接 1 链接的概念 Linux链接分两种 一种被称为硬链接 Hard Link 另一种被称为软链接也叫符号链接 Symbolic Link 默认情况下 ln命令产生硬链接 2 硬链接 在Linux文件系统当中 保存在
  • 年入50万,程序员的第二条赛道

    大家好 我是厂长 我有个朋友 叫佩佩 这几年我亲眼见证了她从月薪6千 到年入百万 她曾经靠一条短视频带货就赚了30万佣金 最近 我看到她在做小红书无货源电商这个风口项目 两个月就做到了单店30万的战绩 她说2023年是小红书电商元年 0粉
  • 回味C语言

    虽然在实际上没怎么使用C语言了 但是看到C语言的书总是忍不住想看一下 喜欢这种至简 却又有着强大能力的语言 读完书随手写的一些笔记 略有些简单 书还是很喜欢的 推荐给大家 C专家编程 第一章 C 穿越时空的迷雾 原型决定C语言不支持函数重载