Skip to main content

C

变量的命名规则

命名规则

作用域前缀,

No.标识符类型作用域前缀
1Global Variableg
2File Static Variable(native)n
3Function Static Variablef
4Auto Variablea
5Global Functiong
6Static Functionn

数据类型前缀命名规则,

No.PrefixSuffixData TypeExampleRemark
1btbitBit btVariable;
2bbooleanboolean bVariable;
3ccharchar cVariable;
4iintint iVariable;
5sshort[int]short[int] sVariable;
6llong[int]long[int] IVariable;
7uunsigned[int]unsigned[int] uiVariable;
8ddoubledouble dVariable;
9ffloatfloat fVariable;
10ppointervoid * vpVariable;指针前缀
11Vvoidvoid vVariable;
13stenumenum A stVariable;
14ststructstruct A stVariable;
15stunionunion A stVariable;
16fpfunction pointervoid(* fpGetModeFuncList_a[])( void )
17-aarray ofchar cVariable_a[TABLE_MAX];
18_st,_psttypedef enum/struct/union
typedef struct SM_EventOpt
{
unsigned char
unsigned int
char
}SM_EventOpt_st,*SM_EventOpt_pst;
当自定义结构数据类型时使用_st 后缀; 当自定义结构数据类型为指针类型时使用_pst后缀

关键字

static

修饰全局变量,作用域仅限于变量被定义的文件中。从定义之处开始,到文件末尾结束。

静态局部变量,在函数体里面定义的,就只能在这个函数里用了。被 static 修饰的变量总是存在内存的静态区,即使这个函数运行结束,这个静态变量的值也不会被销毁。

修饰函数,表示静态函数,指对函数的作用域仅局限于本文件,不用担心自己定与你的函数是否会与其他文件中的函数同名。

数据类型

bool 变量与令旨进行比较

bool bTestFlag = FALSE

if(bTestFlag!=False){
// do
}

推荐 bool 和FALSE(零值)进行比较。 TRUE 的定义在不同的平台可能不一样。不一定是1.

指针变量与“零值”进行比较

if(NULL==p);
if(NULL!=p);

sizeof

int i = 0;

sizeof i // correct
sizeof int // error

sizeof 在计算变量所占空间大小的时候,括号可以省略,而计算类型大小时不能省略。一般情况下无脑添加括号即可。

const

const 修饰的只读变量,const修饰的只读变量必须在定义的时候同时初始化。

const 和宏定义的区别,

#define M 3 // 宏常量
const int N = 5;

const 定义的只读变量在程序运行过程中只有一份拷贝,而 #define 定义的宏常量在内存中有若干个拷贝。 #define 宏是在预编译阶段进行替换,而 const 修饰的只读变量是在编译的时候确认其值。

  • 修饰一般变量,只读变量,
int const i = 2;
const int i = 2;
  • 修饰数组,定义一个只读数组,
int const a[5] = {1,2,3,4,5};
const int a[5] = {1,2,3,4,5};
  • 修饰指针
const int *p; // p 可变,p 指向的对象不可变
int const *p; // p 可变,p 指向的对象不可变
int * const p; // p 不可变,p 指向的对象可变
const int * const p; // p 不可变,p 指向的对象不可变

方便记忆的方法,先忽略类型名,看 const 离哪个近,const 就修饰谁。

const <int> *p; // const 修饰的是 *p, p 是指针,*p 是指针指向的对象,不可变。
<int> const *p; // 同上
<int> * const p; // const 修饰 p, p 不可变, p指向的对象可变。
  • 修饰函数的参数

const 修饰符也可以修饰函数的参数,当不希望这个参数值被函数体内意外修改时使用,例如,

void Fun(const int i);
  • 修饰函数的返回值

返回值不可被改变

const int Fun(void);

volatile

volatile int i = 10;

volatile 关键字告诉编译器 i 是随时可能放生变化的,每次使用它的时候必须从内存中取出 i 的值。

struct

  • 空结构体多大?

在 gcc 上测试了一下是 0 。

#include <stdio.h>

struct student
{
} stu;

int main(int argc, char const *argv[])
{
printf("size of empty stu: %lu\n", sizeof(stu));
return 0;
}
  • 柔性数组(flexible array)

C99 中,结构体中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构体中的柔性数组成员前面必须至少一个其他成员。

#include <stdio.h>
#include <stdlib.h>

typedef struct st_type
{
int i;
int a[];
} type_a;

int main(int argc, char const *argv[])
{
printf("size of empty type_a: %lu\n", sizeof(type_a));

type_a *p = (type_a *)malloc(sizeof(type_a) + 100 * sizeof(int));

printf("size of p: %lu\n", sizeof(*p));
return 0;
}

这里 *ptype_a 的 sizeof 得到的大小是一样的。

union

一个 union 只配置一个足够大的空间以来容纳最大长度的数据成员.

检查系统大小端,

int checkSystem()
{
union check
{
int i;
char ch;
} c;
c.i = 1;
return (c.ch == 1);
}

enum

一般定义如下:

enum enum_type_name
{
ENUM_CONST_1,
ENUM_CONST_2,
...
ENUM_CONST_n
} enum_variable_name;

enum_type_name 类型的变量 enum_variable_name 只能取值为花括号内的任何一个值,如果赋给该类型变量的值不在列表中,则会报错或者警告。

枚举与#define 宏的区别

  • #define 宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值

typedef

给一个已经存在的数据类型,取一个别名,而非定义一个新的数据类型。

typedef struct student
{
//code
}Stu_st,*Stu_pst;

typedef 就是给“struct student ”取了个别名叫“Stu_st”;同时给“struct student *”取了个别名叫“Stu_pst”。

注意以下两种写法,const 都是修饰 stu2_pst 这种数据类型,即 stu1_pst 和 stu2_pst 在定义的时候就需要做初始化,后续不可改变。

    const Stu_pst stu1_pst;
Stu_pst const stu2_pst;

typedef 和 #define 的区别

#define PCHAR char*
PCHAR p3,p4;

typedef char* pchar;
pchar p1,p2;

这里的 p4 不是指针,仅仅是一个 char 类型的字符。

typedef fixed length array

typedef char type24[3];

However, this is probably a very bad idea, because the resulting type is an array type, but users of it won't see that it's an array type. If used as a function argument, it will be passed by reference, not by value, and the sizeof for it will then be wrong.

A better solution would be

typedef struct type24 { char x[3]; } type24;

字符串拼接

C 中实现 string 的拼接,

#include <stdio.h>
#include <stdlib.h>

int main()
{
const char* msg = "123" "456";
printf("%s\n", msg);
return 0;
}

Reference,

https://learn.microsoft.com/en-us/cpp/c-language/string-literal-concatenation?view=msvc-170

https://en.cppreference.com/w/c/language/string_literal

Phases of translation

https://learn.microsoft.com/en-us/cpp/preprocessor/phases-of-translation?view=msvc-170

The GNU C Reference Manual

https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html

Handmade Hero

https://hero.handmade.network/episode/code

https://handmadehero.org/

TODO

C 语言实现泛型编程,

https://www.runoob.com/w3cnote/c-general-function.html