指针,比特位操作

为了找工作,最近在看《程序员面试宝典》第四版,发现之前学习C++都是太肤浅了。原来比特位操作还可以很灵活的运用哈...


1.用一个表达式判断一个数X是不是2的N次方(N为整数),不可用循环语句。

!(X&(X-1))


2.不使用任何中间变量,交换a和b的值。

a = a^b;

b = a^b;

a = a^b;


3.指针和基于比特位运算的小算法


#include <stdio.h>
#include <cmath>

int f(int x, int y)
{
	return (x&y) + ((x^y)>>1);//实质功能:求取两个整数的均值
}

int Add(int x, int y)
{
	if (y == 0)
	{
		return x;
	}
	int sum, carry;
	sum = x^y;             //第一步没有进位的加法运算
	carry = (x&y)<<1;      //第二步进位并且左移运算
	return Add(sum,carry);
}

inline int Max(int x, int y)
{
	return ((x+y) + abs(x-y))/2;//选择两个整数中最大数,新思路
}

inline int max(int a, int b) {return a>=b? a:b;}
inline int min(int a, int b) {return a<=b? a:b;}
inline int medium(int a, int b, int c)
{
	int t1 = max(a,b);
	int t2 = max(b,c);
	int t3 = max(a,c);
	return min(t1,min(t2,t3));
}
int main()
{
	unsigned int a = 0xFFFFFF7;
	unsigned char i = (unsigned char)a;
	
	char* b = (char*)&a;
	/*
	* 等价于:
	* unsigned int *p = &a;
	* char* b = (char*)p;
	*/
	printf("No.1 Pointer problem:\n");
	printf("%08x, %08x \n", i, *b);

	printf("No.2 MeanAdd problem:\n");
	int meanX = f(729,271);
	int addX = Add(2,8);
	printf("%d, %d\n", meanX, addX);


	printf("No.3 Max problem:\n");
	int maxv = Max(3,5);
	printf("%d\n",maxv);

	printf("No.4 Median problem:\n");
	int medianv = medium(3,7,9);
	printf("%d\n",medianv);

	return 0;
}


<think>我们正在处理关于C语言中指针操作的请求。用户希望得到示例和解释。操作通常涉及按位运算符(如&, |, ^, ~, <<, >>)与指针的结合使用。然而,直接对指针进行操作在C语言中是不常见的,因为指针存储的是内存地址,而直接操作地址的可能会引发对齐问题或未定义行为。但是,我们可以通过将指针转换为整类型,然后对整进行操作,再转换回指针来实现。需要注意的是,这种转换可能依赖于实现(implementation-defined)并且可能不可移植。 根据引用[1]和[2],指针在C语言中非常重要,它直接与硬件地址相关。引用[3]和[4]展示了指针的基本使用和通过指针传递参。 我们将重点介绍: 1. 如何安全地将指针转换为整类型以进行操作。 2. 操作的示例(如对齐操作、地址掩码等)。 注意:直接对指针进行操作(如移或掩码)是不允许的,必须先将指针转换为足够大的整类型(如uintptr_t,定义在<stdint.h>中),然后再进行操作。 示例1:使用操作检查指针是否对齐 示例2:使用操作将地址对齐到某个边界 示例3:通过操作从地址中提某些(例如,在嵌入式系统中访问特定的内存映射寄存器) 注意:这些操作通常用于底层系统编程,如操作系统或嵌入式系统。 我们将按照以下步骤: 1. 引入必要的头文件(如<stdint.h>和<stdio.h>)。 2. 声明一个变量并获指针。 3. 将指针转换为uintptr_t类型(一种能够存储指针的整类型)。 4. 对转换后的整进行操作。 5. 将结果转换回指针类型(如果需要)。 注意:转换回指针类型后,必须确保地址是有效的,否则解引用可能会导致未定义行为。 下面我们给出两个示例。</think>### C语言指针操作详解与示例 在C语言中,指针操作的结合常用于底层系统编程、内存管理和硬件交互等场景。以下是关键概念和示例: --- #### 一、指针操作基础 1. **指针本质** 指针存储的是内存地址,本质上是整(如`0x7ffd42a8`)。因此可以通过整操作修改地址值。 2. **安全转换类型** 需使用`uintptr_t`(定义在`<stdint.h>`中)进行指针⇄整转换,确保安全: ```c #include <stdint.h> void* ptr = ...; uintptr_t int_addr = (uintptr_t)ptr; // 指针→整 void* new_ptr = (void*)int_addr; // 整指针 ``` 3. **常用操作符** - `&`(与)` | `(或)` ^ `(异或)` ~ `(反) - `<<`(左移)` >> `(右移) --- #### 二、典型应用示例 ##### 1. 地址对齐检查 ```c #include <stdio.h> #include <stdint.h> int is_aligned(void* ptr, size_t alignment) { uintptr_t addr = (uintptr_t)ptr; return (addr & (alignment - 1)) == 0; // 检查是否对齐到alignment边界 } int main() { int x; printf("Address %p is 4-byte aligned? %s\n", &x, is_aligned(&x, 4) ? "Yes" : "No"); return 0; } ``` **原理**:对齐到 $2^n$ 的地址,其低 $n$ 必为0。例如4字节对齐时,地址需满足 `addr & 0x3 == 0`[^3]。 ##### 2. 强制地址对齐 ```c void* align_address(void* ptr, size_t alignment) { uintptr_t addr = (uintptr_t)ptr; uintptr_t aligned_addr = (addr + (alignment - 1)) & ~(alignment - 1); return (void*)aligned_addr; } int main() { char buffer[64]; void* raw_addr = &buffer[3]; // 未对齐地址 void* aligned = align_address(raw_addr, 16); printf("Raw: %p → Aligned: %p\n", raw_addr, aligned); return 0; } ``` **原理**:`(addr + align-1)` 确保跨越边界,`& ~(align-1)` 清除低 $n$ 实现对齐[^4]。 ##### 3. 提地址中的页号(内存分页) ```c #define PAGE_SIZE 4096 uint32_t get_page_number(void* ptr) { uintptr_t addr = (uintptr_t)ptr; return addr >> 12; // 右移12(因4096=2^12) } int main() { int data; printf("Page number of %p is %u\n", &data, get_page_number(&data)); return 0; } ``` **原理**:内存分页中,高 $20$ 为页号,低 $12$ 为页内偏移。 ##### 4. 自定义内存分配器(图管理) ```c #include <stdbool.h> #define MEM_SIZE 1024 char memory[MEM_SIZE]; bool bitmap[MEM_SIZE / 8]; // 图:1bit管理1字节 void* bit_alloc(size_t size) { for (int i = 0; i < sizeof(bitmap); i++) { if (bitmap[i] != 0xFF) { // 寻找空闲块 for (int j = 0; j < 8; j++) { if (!(bitmap[i] & (1 << j))) { // 检查第j bitmap[i] |= (1 << j); // 标记为已用 return &memory[i * 8 + j]; // 返回地址 } } } } return NULL; // 内存不足 } ``` **原理**:用图的每个比特位表示内存块的使用状态[^1]。 --- #### 三、注意事项 1. **平台依赖性** 地址长度(32/64)影响操作,需使用`uintptr_t`保证可移植性。 2. **未定义行为** 直接对指针进行位运算(如`ptr << 3`)是未定义行为,必须先转换为整[^2]。 3. **内存安全** 修改后的地址必须有效,否则解引用会导致段错误。 4. **字节序问题** 操作结果受CPU字节序(大端/小端)影响。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Digital2Slave

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值