Pwn 基础之C/C++(一):从第一个 C 程序到数据类型
本篇目标:能够编译 C 程序,看懂变量声明,并理解整数、字符和字节之间的关系。
系列定位:面向 C/C++ 零基础读者,为后续学习二进制程序打基础;本文不讲漏洞利用。
预计阅读时间:15~20 分钟。
1. 第一个 C 程序
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}
保存为 hello.c,然后编译、运行:
gcc hello.c -o hello
./hello
其中:
#include <stdio.h>引入标准输入输出函数的声明;main是程序入口;printf向标准输出打印内容;\n表示换行;return 0表示程序正常结束。
带命令行参数的入口可以写成:
int main(int argc, char *argv[])
{
return 0;
}
argc 是参数数量,argv 保存各参数字符串的地址。
2. 变量是什么
变量是一块有名称、有类型的存储空间:
int age = 18;
char grade = 'A';
double score = 95.5;
声明的一般形式是:
类型 变量名 = 初始值;
类型决定了编译器如何解释这块数据,以及通常需要读取多少字节。
3. 常用数据类型
char c = 'A';
short s = 100;
int i = 1000;
long l = 10000;
long long ll = 100000;
float f = 3.14f;
double d = 3.1415926;
在常见 Linux x86-64 环境中:
| 类型 | 常见大小 |
|---|---|
char |
1 字节 |
short |
2 字节 |
int |
4 字节 |
long |
8 字节 |
long long |
8 字节 |
float |
4 字节 |
double |
8 字节 |
| 指针 | 8 字节 |
这些大小与平台和 ABI 有关,应该用 sizeof 验证:
#include <stdio.h>
int main(void)
{
printf("char: %zu\n", sizeof(char));
printf("int: %zu\n", sizeof(int));
printf("long: %zu\n", sizeof(long));
printf("pointer: %zu\n", sizeof(void *));
return 0;
}
4. 位、字节和十六进制
现代计算机中通常有:
1 byte = 8 bit
一个 bit 只能取 0 或 1。一个字节共有 2^8 = 256 种状态。
十六进制很适合表示内存:
1 个十六进制数字 = 4 bit
2 个十六进制数字 = 1 byte
C 中的十六进制整数以 0x 开头:
int a = 16;
int b = 0x10;
a 和 b 的值相同。
printf("decimal: %d\n", b);
printf("hex: 0x%x\n", b);
5. 固定宽度整数
处理二进制数据时,常用 <stdint.h> 中的类型:
#include <stdint.h>
uint8_t a = 1;
uint16_t b = 2;
uint32_t c = 3;
uint64_t d = 4;
int8_t e = -1;
int32_t f = -100;
u表示无符号;- 数字表示位数;
_t表示这是一个类型名。
6. 有符号、无符号与补码
int signed_value = -1;
unsigned int unsigned_value = 1;
32 位整数的常见范围:
int32_t: -2^31 ~ 2^31-1
uint32_t: 0 ~ 2^32-1
现代计算机通常使用补码表示负数。以 8 位的 -5 为例:
5 = 00000101
按位取反 = 11111010
加一 = 11111011
同一组字节可以被解释成有符号数或无符号数。因此,分析表达式时必须同时关注“值”和“类型”。
7. 字符本质上也是整数
char ch = 'A';
printf("character: %c\n", ch);
printf("decimal: %d\n", ch);
printf("hex: 0x%x\n", (unsigned char)ch);
ASCII 中常见值:
'A' = 65 = 0x41
'a' = 97 = 0x61
'0' = 48 = 0x30
'\n' = 10 = 0x0a
8. 基础运算符
int a = 10;
int b = 3;
int sum = a + b;
int sub = a - b;
int mul = a * b;
int div = a / b;
int mod = a % b;
整数除法会舍弃小数部分:
printf("%d\n", 5 / 2); // 2
printf("%f\n", 5.0 / 2.0); // 2.500000
比较运算符:
== != > < >= <=
逻辑运算符:
&& || !
位运算符:
& | ^ ~ << >>
例如判断最低位:
if (value & 1) {
printf("odd\n");
}
本篇练习
- 编写程序打印所有基础类型的
sizeof。 - 输入一个整数,分别以十进制和十六进制输出。
- 输出字符
A、a、0的数值。 - 使用位运算判断一个整数的奇偶性。
- 分别使用
int32_t和uint32_t保存数据并观察输出。
本篇小结
- C 程序从
main开始执行; - 类型决定数据的大小和解释方式;
- 内存以字节为基本观察单位;
- 十六进制便于表示地址和原始字节;
- 字符也是整数;
- 阅读整数表达式时必须关注位宽和符号属性。
下一篇
下一篇学习条件、循环、函数、作用域和按值传递,让程序真正具备处理逻辑。

说些什么吧!