贡献者: addis
gcc 的 C 语言标准有 -std=c90,c99,c11,c17,c2x 若要使用 GNU 拓展,也可以用 gnu99 等。
__STDC_VERSION__ 可以在程序中判断编译器的 C 标准。例如 199901L 就是 c99 标准,201112L 就是 c11 标准。L 表示 long int 的 literal。打印如 printf("C version: %ld\n", __STDC_VERSION__);
#include "string.h"
char s1[20] = "some string1";
char s2[20] = "some string2";
strlen(s1) // 字符串长度
strcpy(s1, s2) // 复制(s2 可以是 literal)
strcmp(s1, s2) // 比较
strcat(s1, s2) // 连接
strrev(s1) // 反转
#include<stdio.h>
void main()
{
char s[20];
scanf("%s",&s);
printf("%s\n",s);
}
具体的格式代码见这里。
int i = 1234;
printf("=== int ===\n");
printf("%6.5d\n", i); // " 01234"
printf("=== string ===\n");
string s = "abcdABCD";
printf("%s\n", s.c_str()); // "abcdABCD"
double x = 12.345;
printf("=== double 1 ===\n");
printf("%8.3f\n", x); // " 12.345"
printf("%10.3e\n", x); // " 1.235e+01"
printf("%g\n", x); // "12.345"
printf("%5.3g\n", x); // " 12.3"
double y = 0.000012345678;
printf("=== double 2 ===\n");
printf("%g\n", y); // "1.23457e-05"
printf("%10.3g\n", y); // " 1.23e-05"
如果不想输出到命令行而是输出到字符串,就用 int sprintf(char *str, const char *format, ...)。返回写入的字符数。该函数返回写入到 str 的总字符数。
#include <stdio.h>
int main()
{
int x,y,z;
scanf("%d+\n,\n=%d",&x,&y);
z=x*y;
printf("x=%d,y=%d\n",x,y);
printf("xy=%d\n",z);
}
// 输入:
// 123+
// ,
// =234
// 输出:
// x=123,y=234
// xy=28782
引号内除了特殊字符,其它都需要输入一摸一样的,否则会出错。但是,1.变量前面可以多打任意多个空格和回车(后面不可以),2.任意多个空格或回车相连等效。
#include <stdio.h>
#include <string.h>
void main()
{
int i=1;
char str[5]={0};
while(i<=5)
{str[i]=getchar();i++;}
i=1;
while(i<=5)
{printf("%d ",str[i]);i++;}
printf("\n");
i=1;
while(i<=5)
{printf("%c",str[i]);i++;}
printf("\n");
}
union 和 struct 类似,但变量共用内存
struct 名称 {} // 声明变量: struct 名称 变量
enum 名称 {} // 声明变量: enum 名称 变量
union 名称 {} // 声明变量: union 名称 变量
typedef struct {} 名称 // 声明变量: 名称 变量
typedef enum {} 名称 // 同理
typedef union {} 名称 // 同理
两种定义方式的使用方法并不完全等效(该代码已使用 g++ 和 gcc 的不同标准测试)。最简单的记忆方法就是第一种声明在使用时需要加 enum,第二种声明不用。
enum B {B1, B2};
enum B b1; // GOOD in C++ and c
// B b2; // good in C++, error in c: unknown type name ‘B’
typedef enum B BB; // GOOD in C++ and c
// typedef B BBB; // good in C++, error in c
// ==========================
typedef enum {A1, A2} A;
A a1; // GOOD in C++ and c
// enum A a2; // error in C++ and c
// error: using typedef-name ‘A’ after ‘enum’
typedef A AA; // GOOD in C++ and c
// typedef enum A C; // error in C++, good in c
匿名 structure:
void myfun(struct {int a; double b;} param) {
/*...*/
}
int main() {
struct {
int i;
double d;
} var1{1,1.1}, var2{2,2.2};
myfun(var1);
myfun(var2);
}
注意匿名 structure 只能传给接受同样匿名 structure 的函数,不能给接受实名 structure 的函数,即使函数结构一样。
// 函数指针(每个括号左右都可以有空格)
double(*p1)(double) = sin; // 也可以用 &sin,下同
// 定义函数指针类
typedef double(*Tpf)(double);
Tpf p3 = sin;
// 定义函数类
typedef double(Tf)(double);
Tf *p2 = sin; // 注意 `Tf my_fun;` 是非法的
// 作为类型参数
vector<double(*)(double)> arr{&sin, cos};
// 调用函数(dereference 可选)
cout << "sin(1) = " << arr[0](1) << endl;
cout << "cos(1) = " << (*arr[1])(1) << endl;
要获取函数指针,既可以用 函数名 也可以用 &函数名。
见 C 语言文件处理笔记。
void *malloc(size_t size); 分配内存,如果失败返回 NULL。
void free(void *ptr); 释放内存。
void *realloc(void *ptr, size_t new_size); 会保留之前的数据。如果可以延长内存就延长,如果不能就重新分配并复制。新分配的数据不会初始化。如果失败返回 NULL。
__attribute__((constructor)) 可以在本 c/cpp 的 dll 或可执行文件加载时运行该函数。若 c/cpp 中定义了 main() 就在它之前运行。若该文件被编译为 dll,就在 dll 加载时运行(例如 dlopen)
__auto_type 相当于 C++ 中的 auto 可以自动推导类型。
({...; ...;}) 可以执行多个语句,并把最后一个语句的值返回。
__builtin_constant_p(expr) 是一个编译期内建函数,用于判断编译器是否能够在编译阶段确定某个表达式是常量。
( 才可以匹配! 否则就会忽略该函数。如 (名字)(参数1, 参数2) 可以调用一个与宏函数同名的普通函数。
<stdatomic.h> 中,_Atomic(类型) 变量; 用于声明该变量单线程一次操作是一个整体(概念上相当于加锁,但 CPU 可以有等效的无锁实现)。另外对内建类型也可以直接等效用 atomic_int 等。可以使用以下原子操作。
atomic_int x = 0;
atomic_store(&x, 10); // write
int v = atomic_load(&x); // read
atomic_fetch_add(&x, 2); // atomically increment (x += 2)
atomic_fetch_sub(&x, 2); // atomically decrement (x -= 2)
atomic_exchange(&x, 5); // atomically set x = 5, return old value
atomic_store/load 是最严格的,等效于 atomic_store/load_explicit(xxx, memory_order_seq_cst),适合新手,可以假设顺序就是代码中的那样,且立刻生效。但性能最低。
atomic_store/load_explicit(xxx, memory_order_relaxed),可能顺序打乱也未必立刻生效,只保证单次操作是原子的。性能最高。
atomic_store_explicit(xxx, memory_order_release) 和 load_explicit(xxx, memory_order_acquire)。同样不能保证立即生效,但保证 release 之前写入的所有变量会在 acquire 之后读到。
<stddef.h> 中的 offsetof(struct或union类名, 字段名) 宏函数可以找到字段离对象开头的字节偏移,返回 size_t。标准的 C 中,第一个字段名的偏移一定是 0。
static inline 中 static 表示 internal linkage(只有当前编译单元可见),inline 和 C++ 一样建议 inline。用宏 STATIC_INLINE 宏会更可移植。一般定义如下
#ifdef _MSC_VER
# define STATIC_INLINE static __inline
#else
# define STATIC_INLINE static inline
#endif