C - Charles-Charmless/Charles-Charmless.github.io GitHub Wiki

C语言技巧

  • 判断逻辑关系的时候将常量写在前面,变量写在后面
  • 合法的赋值形式要求两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须具有右边指针所指向类型的全部限定符。

scanf,gets,getchar

gets以一行为单位,可以读取有空格的字符串, getchar以字符为单位读取,可以避免长度限制 scanf以空格为间隔,在读取到行末时不会读取换行符,而是在下一次读取时取出

将char型声明为整型可以确保不会由多个字符连接被误认为EOF

地址按照字节来计算而不是按照位来计算

如果只创建指针但是没有初始化,那么程序并不会给指针创建存储空间

NULL表示某个特定的指针目前并未指向任何东西

Cbug

#/##

在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication)

而##被称为连接符(concatenator),用来将两个Token连接为一个Token

Name Tags Files
_LINE_ 正在编译的文件的行号
_FILE_ 正在编译的文件的名字
_DATE_ 编译时可的日期字符串
_TIME_ 编译时刻的时间字符串
_STDC_ 判断程序是否为标准的c程序

预编译

gcc

预处理

预处理指令 含义
define 宏定义
undef 撤销已定义的宏名
include 使编译程序将另一个源文件嵌入到带有#include的源文件中
if
else
elif
endif
ifdef
ifndef
line
error
pragma

数据类型

无符号数和有符号数一起运算会转换成无符号数进行转换

关键字

static

  1. 定义全局静态变量:在全局变量前面加上关键字static,该全局变量变成了全局静态变量。全局静态变量有以下特点。a.在全局区分配内存。b.如果没有初始化,其默认值为0.c.该变量在本文件内从定义开始到文件结束可见。

  2. 定义局部静态变量:在局部变量前面加上关键字static,其特点如下:a.该变量在全局数据区分配内存。b.它始终驻留在全局数据区,直到程序运行结束。c. 其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。

  3. 定义静态函数:在函数返回类型前加上static关键字,函数即被定义为静态函数,其特点如下:

    a.静态函数只能在本源文件中使用 b.在文件作用域中声明的inline函数默认为static类型

用static定义的全局和局部静态变量的区别是,全局的静态变量的作用域和可见域都是从文件的定义开始到整个文件结束;而局部的静态变量可见域是从文件的定义开始到整个文件结束,作用域是从该语句块的定义开始到该语句块结束。

static关键字定义静态常量,存储在系统的全局初始化区

const

可以定义const常量,具有不可变性。

c语言中const全局变量存储在只读数据段,编译期最初将其保存在符号表中,第一次使用时为其分配内存,在程序结束时释放。

==const 从左向右结合,不考虑定义符int ,float等==

  • const int * p;
int a=10;
const int *p=20;
*p=30;//错误
p=&a; //正确
  • int const * p;同const int *p
  • int * const p;
int a=10;
int * const p=20;
*p=30;//正确
p=&a;//错误
  • int const * const p;
int a=10;
int const * const p;
*p=30;//错误
p=&a;//错误

volatile

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

例如中断改变寄存器数据;

共享内存

汇编的任意操作

struct

将可能不同类型的对象聚合到一个对象中

union

允许用多种类型来引用一个对象

循环方式

while

for

goto

函数

  • 函数前面加两个下划线表示内部函数

内联函数

关键字:inline,__inline,__forceinline

任何地方只要调用内联函数,就直接把该函数的机器码插入到调用它的地方。这样程序执行更有效率,就好像将内联函数中的语句直接插入到了源代码文件中需要调用该函数的地方一样。

inline 修饰符并非强制性的:编译器有可能会置之不理。

区别于宏

内联函数时代码被插到调用者代码处的函数。避免调用的开销

宏由预处理器对宏进行替换,内联函数通过编译器控制实现,内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。

宏不检查参数类型,内联函数检查参数类型。

指针数组/数组指针

==‘[]’的优先级比'*'的优先级高==

/*****************************************/
int *p1[10];              //数组指针
int (*p2)[10];            //指针数组

int main(void){
    int *p1[4];
    int (*p2)[4];
    printf(" the byte of the pointer of array is %d\n",sizeof(p1));
    printf(" the byte of the pointer in the array is %d",sizeof(p2));
    return  0;
}

the byte of the pointer of array is 32
the byte of the pointer in the array is 8

这是什么鬼?

int main(void){
    char *m='m';
    printf("%d\n",m+1);
    printf("%d\n",(int*)(m+1));
    printf("%d\n",(int *)m+1);
    return  0;
}

============================================
110
110
113

指针的强制类型转换只改变类型,不改变他的值

强制类型转换的一个效果是改变指针运算的伸缩

关于C语言头文件的问题

\#include < > 直接从编辑器自带的函数库中寻找文件#include " " 先从自定义的文件中找,如果找不到再从库函数中寻找文件,并且可以在 #include “ “中使用相对路径或者绝对路径来指定头文件所在的位置

⚠️ **GitHub.com Fallback** ⚠️