第一部分
C和ASM作为基础, 要长相看,莫相忘......
1. 数据类型
1.1 整数
以下是基本整数关键字:
* char : 有符号8位整数;
* short : 有符号16位整数;
* int : 有符号32位整数;
* long : 在32位系统上是32位整数, 在64位系统上则是64位整数;
* long long : 有符号64位整数;
* bool : _Bool类型, 8位整数, 在<stdbool.h>种定义了宏bool, true, false, 方便使用。
由于在不同系统上, char可能代表有符号或无符号8位整数, 因此建议使用unsigned char / signed char来表示具体的类型。
在<stdint.h>中定义的一些看上去更明确的整数类型:
typedef signed char int8_t; typedef short int int16_t; typedef int int32_t; typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; #if __WORDSIZE == 64 typedef long int int64_t; typedef unsigned long int uint64_t; #else __extension__ typedef long long int int64_t; typedef unsigned long long int uint64_t; #endif
还定义了各种整数类型的大小限制:
/* Limits of integral types. */ /* Minimum of signed integral types. */ # define INT8_MIN (-128) # define INT16_MIN (-32767-1) # define INT32_MIN (-2147483647-1) # define INT64_MIN (-__INT64_C(9223372036854775807)-1) /* Maximum of signed integral types. */ # define INT8_MAX (127) # define INT16_MAX (32767) # define INT32_MAX (2147483647) # define INT64_MAX (__INT64_C(9223372036854775807)) /* Maximum of unsigned integral types. */ # define UINT8_MAX (255) # define UINT16_MAX (65535) # define UINT32_MAX (4294967295U) # define UINT64_MAX (__UINT64_C(18446744073709551615))
字符常量默认位一个 int 整数, 但编译器可以自行决定将其解释为 char 或 int :
char c = 'a'; printf("%c, size(char)=%d, size('a')=%d; ", c, sizeof(c), sizeof('a')); // 输出: a, size(char)=1, size('a')=4;
指针是个很有特殊用途的整数, <stdint.h>中同样给出了其类型定义:
/* Types for `void *' pointers. */ #if __WORDSIZE == 64 # ifndef __intptr_t_defined typedef long int intptr_t; # define __intptr_t_defined # endif typedef unsigned long int uintptr_t; #else # ifndef __intptr_t_defined typedef int intptr_t; # define __intptr_t_defined # endif typedef unsigned int uintptr_t; #endif
不过, 在代码中,我们通常菜用sizeof(char*)这样的用法, 省去处理32位和64位指针的区别。
我们可以使用不同的后缀来表示整数常量类型:
printf("int size=%d; ", sizeof(1)); // 输出: int size=4; printf("unsigned int size=%d; ", sizeof(1U)); // 输出: unsigned int size=4; printf("long size=%d; ", sizeof(1L)); // 输出: long size=4; printf("unsigned long size=%d; ", sizeof(1UL)); // 输出: unsigned long size=4; printf("long long size=%d; ", sizeof(1LL)); // 输出: long long size=8; printf("unsigned long long size=%d; ", sizeof(1ULL)); // 输出: unsigned long long size=8;
<stdint.h>中定义的一些辅助宏:
# if __WORDSIZE == 64 # define __INT64_C(c) c ## L # define __UINT64_C(c) c ## UL # else # define __INT64_C(c) c ## LL # define __UINT64_C(c) c ## ULL # endif ... /* Signed. */ # define INT8_C(c) c # define INT16_C(c) c # define INT32_C(c) c # if __WORDSIZE == 64 # define INT64_C(c) c ## L # else # define INT64_C(c) c ## LL # endif /* Unsigned. */ # define UINT8_C(c) c # define UINT16_C(c) c # define UINT32_C(c) c ## U # if __WORDSIZE == 64 # define UINT64_C(c) c ## UL # else # define UINT64_C(c) c ## ULL # endif
注: 宏定义种的"##"运算符将左右两侧的操作数接合在一起, 作为一个记号!
1.2 浮点数
C 提供了不同精度的浮点数:
* float : 32位浮点数, 精度为 6 位小数;
* double : 64位浮点数, 精度为 15 位小数;
* long double : 80位浮点数, 精度为 19 位小数。
浮点数默认类型为 double , 可以添加后缀 F 来表示 float , L 表示 long double , 可以局部忽略。
printf("float %f size=%d ", 1.F, sizeof(1.F)); // 输出: float 1.000000 size=4 printf("double %f size=%d ", .123, sizeof(.123)); // 输出: double 0.123000 size=8 printf("long double %Lf size=%d ", 1.234L, sizeof(1.234L));// 输出: long double 1.234000 size=12 # 对齐
C99 提供了复数支持, 用两个相同类型的浮点数分别表示复数的实部和虚部。
直接在float、double、long double 后添加_Complex 即可表示复数, 在 <complex.h> 中定义了 complex 宏使得显示更统一美观。
#include <complex.h> printf("float complex size=%d ", sizeof((float complex)1.0)); // 输出: float complex size=8 printf("double complex size=%d ", sizeof((double complex)1.0)); // 输出: double complex size=16 printf("long double complex size=%d ", sizeof((long double complex)1.0)); // 输出: long double complex size=24
1.3 枚举
enum color { black, red = 5, green, yellow }; enum color b = black; printf("black = %d ", b); // 输出: black = 0 enum color r = red; printf("red = %d ", r); // 输出: red = 5 enum color g = green; printf("green = %d ", g); // 输出: green = 6 enum color y = yellow; printf("yellow = %d ", y); // 输出: yellow = 7
注: 枚举成员的值可以相同!
通常省略枚举标签来代替宏定义常量:
enum { BLACK = 1, RED, GREEN = 1, YELLOW }; printf("black = %d ", BLACK); // 输出: black = 1 printf("red = %d ", RED); // 输出: red = 2 printf("green = %d ", GREEN); // 输出: green = 1 printf("yellow = %d ", YELLOW); // 输出: yellow = 2
2. 字面值
字面值(literal)是源码种用来描述固定值的记号(token), 可以是整数、浮点数、字符和字符串。
2.1 整数常量
常见的有: 十进制常量、八进制常量(0开头)、十六进制常量(0x/0X开头)。
常量的类型很重要, 主要通过后缀来区分类型:
0x200 -> int 200U -> unsigned int 0L -> long 0xf0f0UL -> unsigned long 0777LL -> long long 0xFFULL -> unsigned long long
2.2 浮点常量
浮点数常量常用十进制数、十六进制数来表示 。
默认浮点常量是 double 型, 可以使用 F 后缀来表示 float 型, 用 L 后缀来表示 long double 型。
2.3 字符常量
字符常量默认是 int 型, 除非使用前置 L 来表示 wchar_t 宽字符类型。
在 Linux 系统中, 默认字符集是 UTF-8 , 可以使用 wctomb 等函数进行转换。wchar_t 默认是 4 字节长度, 足以容纳所有 UCS-4 Unicode 字符。
#include <stdio.h> #include <locale.h> #include <stdlib.h> int main(int argc, char* argv[]) { setlocale(LC_CTYPE, "en_US.UTF-8"); char buf[128] = {}; wchar_t wc=L'中'; int len = wctomb(buf, wc); printf("%d ", len); for(int i=0; i<len; i++) { printf("0x%02X ", (unsigned char)buf[i]); } printf(" "); return 0; }
2.4 字符串常量
C语言种的字符串是一个以 NUL ( '