写一个函数判断机器字长 (不用sizeof函数)

本文介绍了一种使用C语言计算机器字长的方法。通过利用指针和sizeof运算符,程序能够准确地确定系统的指针大小,进而反映出机器的字长。这种方法适用于不同架构的计算机系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>


/* using sizeof long int */

int word_size()  

{

    void *p;

    return sizeof(p);     /* the length of pointer */

}


/* using pointer */

int word_size()

{

    void **ptr;

     // 这里如果没用强制类型转换(unsigned long),编译器就会优化这个语句成:ptr+1-ptr,结果就成1了

    return ((unsigned long)(ptr+1)-(unsigned long)(ptr));   /* the length of pointer variable */

}


int main()

{

    printf("The size of machine word is %d\n", word_size());

}


<think>我们要求实现一个函数,输入是一个无符号长整型(unsigned long),输出也是无符号长整型。 功能:从高位到低位扫描二进制位,将连续的“101”替换为“011”,并且替换过的位不再参与后续的替换(即跳过替换过的位)。 例如:假设输入是0b101010(二进制),我们将其看作6位:101010 从高位开始扫描: 首先看到最高三位是101,将其替换为011,得到011010,然后跳过这三位(已经替换过的三位),继续处理后面的位。 接下来三位是010,其中没有连续的101,所以不变。 因此最终结果为011010,即0x1A(十六进制)或26(十进制)。 注意:由于是无符号长整型,我们假设是32位或64位,但题目没有指定,我们按通用的机器字长(例如64位)来处理,但实际上算法与位数无关。 思路: 由于要求从高位到低位扫描,并且替换后跳过已替换的位,我们可以逐位检查,每次检查连续的三个位。 但是,由于替换后跳过三位,我们可以每次移动三位。然而,替换后可能影响后续的位模式,但题目要求跳过替换过的位,所以替换后我们直接跳过这三位的处理,继续处理后面的位。 然而,这里有一个问题:替换后,新的三位中的后两位(即“11”)可能与后面的位组成新的“101”吗?但是题目要求跳过替换过的位,所以替换后我们直接跳到下一个三位组(即从当前位之后的三位开始)。 但是,如果我们从高位开始,每次处理三位,然后移动三位,那么就不会出现重叠。因为替换后我们跳过这三位,继续处理后面的三位。 因此,我们可以这样: 从最高位开始,每次取三位(即从第i位开始的连续三位,i从0开始,0表示最高位),判断这三位是否是101,如果是,则替换为011,然后跳过这三位(即i+=3);如果不是,则移动一位(i+=1)继续检查。 但是,由于二进制位操作,我们需要在无符号长整型上操作。我们可以使用一个掩码(mask)来取出连续的三个位。 然而,由于我们是从高位到低位,所以我们可以用一个掩码,初始为0b111000...000(即最高三位为1,其余为0),然后每次右移一位(对于移动一位的情况)或三位(对于替换后跳过的情况)。 但是,我们也可以用一个循环,从最高位开始,每次检查连续的三个位,直到处理到没有足够的三个位(即剩余位数不足三位)。 步骤: 1. 初始化一个结果变量result为0。 2. 初始化一个掩码mask,用于取出连续的三个位。由于从最高位开始,掩码应该覆盖最高的三位。例如,对于64位,掩码初始为0xE000000000000000(即二进制的111后面跟着61个0)。 3. 初始化一个位置指针pos,表示当前处理的位置(从0开始,0表示最高位的位置)。 4. 循环,当pos <= (总位数-3) 时: 取出当前三个位:value = (input_int & mask) >> (总位数-3-pos) [这样可以将这三个位移到最低三位] 或者,我们可以通过移位操作将当前的三位移到最高位,然后与7(即二进制的111)比较?这样可能更简单。 另一种思路:将输入整数看作一个二进制位数组,但我们无法直接操作数组,所以用位操作。 为了便于操作,我们可以将输入整数左移,使得当前要检查的位处于最高位,然后取最高三位。 具体: 令current = input_int << pos; 这样,当前要检查的位就位于current的最高位。 然后,取current的最高三位:three_bits = current >> (sizeof(unsigned long)*8 - 3); 然后判断three_bits是否等于0b101(即5): 如果是,则在结果的对应位置(从pos开始的三位)放入011(即0b011,也就是3),然后pos += 3; 如果不是,则将当前位(即最高位)保留,然后pos += 1。 但是,这样我们如何构建结果呢?我们需要在result中设置相应的位。 我们可以: 初始化result为0,然后从高位开始,逐位或上相应的值。 具体步骤: 设总位数 = sizeof(unsigned long)*8,设为total_bits。 初始化result=0,pos=0。 当pos < total_bits: 如果剩余位数不足3位(即total_bits - pos < 3),则直接将剩余位复制到result中,然后跳出循环。 否则: 取当前pos开始的三个位(即从高到低第pos位开始的三位): current = input_int << pos; // 将当前pos位移到最高位 three_bits = current >> (total_bits-3); // 这样three_bits就是当前三个位的值(在最低三位) 如果three_bits == 0x5(二进制101): 则我们在result的对应位置(从pos位开始)设置011(二进制011,即0x3): 将011左移到适当的位置:我们需要将0x3左移(total_bits-3-pos)位,这样这三个位就会放在result的从pos位开始的位置。 result |= (0x3ULL << (total_bits-3-pos)); // 注意:这里使用ULL后缀确保无符号长整型 然后pos += 3; // 跳过三位 否则: 我们只处理当前第一个位(即pos位置上的位): 取当前位的值:取three_bits的最高位(即three_bits>>2,因为three_bits是三位,最高位是第2位): bit = (three_bits >> 2) & 0x1; // 这样得到当前最高位(也就是原数的第pos位)的值 将这个位设置到result的对应位置(第pos位): 我们需要将bit左移(total_bits-1-pos)位,这样它就在result的第pos位(最高位为0位置)。 result |= (bit << (total_bits-1-pos)); 然后pos += 1; 注意:由于我们是从高位开始,所以位置编号0表示最高位,位置编号1表示次高位,以此类推。 但是,这里有一个问题:当我们处理完三位后,我们跳过了三位,然后继续处理后面的位。但是,当我们处理一位时,我们只设置了一位,然后移动到下一位。 这个算法可以,但是需要小心位操作。 然而,我们也可以换一种方式:不改变原始输入,而是用一个指针扫描,然后构建新的结果。 另一种更简单的方法:我们用一个循环,每次处理一位,但当我们匹配到101时,我们一次处理三位。我们可以使用一个状态机?但这里模式固定,所以可以直接匹配。 我们考虑使用一个循环,从最高位到最低位,用索引i(0<=i<total_bits): 如果i<=total_bits-3并且当前从i开始的三个位是101,那么我们在结果中设置011,然后i增加3(跳过三位)。 否则,我们设置当前位(i位置)为原始位,然后i增加1。 问题是如何设置结果中的位?我们可以用一个变量result,然后按位设置。 具体: 初始化result=0,i=0。 循环直到i>=total_bits: 如果i<=total_bits-3: 取出从i开始的三个位:temp = (input_int >> (total_bits-1-i)) & 0x7; // 这样将第i位开始的三个位移到最低三位 注意:因为我们是从高位开始,所以第i位就是最高位后的第i位。例如,最高位(第0位)是最高位,第1位是次高位。 移位操作:为了取出从第i位开始的连续三位,我们可以将input_int左移i位,这样第i位就到了最高位,然后取最高三位(右移total_bits-3位?)或者直接右移(total_bits-3-i)位?这样比较复杂。 另一种取法:我们想要取从i位开始的三位,那么可以: mask = (0x7ULL << (total_bits-1-i)); // 这样mask覆盖了从i位开始的三位 temp = (input_int & mask) >> (total_bits-1-i-2); // 这样temp就是这三位组成的数(在最低三位),但是注意:total_bits-1-i是最高位的位置,我们想取的三位是从i(高位)到i+2(低位),所以移位需要移动(total_bits-1-i-2)位?这样不对。 实际上,如果我们有total_bits位,那么第i位(0<=i<total_bits)的权重是(total_bits-1-i)。所以,我们想取的三位(i, i+1, i+2)的权重分别是(total_bits-1-i), (total_bits-1-i-1), (total_bits-1-i-2)。所以,我们可以: temp = (input_int >> (total_bits-1-i-2)) & 0x7; // 这样,我们将最低位(i+2位)移到最低位,然后取最低三位。 但是,这样移位后,第i位(最高位)在temp的最高位(第2位),第i+1位在中间(第1位),第i+2位在最低位(第0位)。所以temp就是这三位组成的数。 例如:total_bits=6,i=0,那么我们要取第0,1,2位: 移位:右移(6-1-0-2)=3位,即右移3位,然后取低三位。因为原始位:第0位(最高位)在5的位置,第1位在4,第2位在3,右移3位后,第0位到了2的位置,第1位到1,第2位到0,所以低三位就是这三位。 所以,公式:temp = (input_int >> (total_bits-3-i)) & 0x7; 然后,如果temp==0x5(二进制101),那么: 我们设置结果中从i开始的三个位为0x3(011): 将0x3左移(total_bits-3-i)位,然后或到result上。 result |= (0x3ULL << (total_bits-3-i)); i += 3; 否则: 设置第i位:取temp的最高位(即(temp>>2)&1),然后设置到result的对应位置(第i位): bit = (temp >> 2) & 1; result |= (bit << (total_bits-1-i)); // 第i位的权重是total_bits-1-i i += 1; 注意:当i>total_bits-3时,即剩余不足三位,那么我们就不能取三位了,只能一位一位处理。 所以,循环可以这样: unsigned long pattern_replace(unsigned long input_int) { int total_bits = sizeof(unsigned long) * 8; unsigned long result = 0; int i = 0; while (i < total_bits) { // 如果剩余位数大于等于3位 if (i <= total_bits - 3) { // 取出从i开始的三位 unsigned long temp = (input_int >> (total_bits - 3 - i)) & 0x7; if (temp == 0x5) { // 0x5是二进制101 // 将011(0x3)放到结果中对应的位置 result |= (0x3ULL << (total_bits - 3 - i)); i += 3; // 跳过三位 } else { // 只取当前位(即三位中的最高位) unsigned long bit = (temp >> 2) & 0x1; // 取最高位 result |= (bit << (total_bits - 1 - i)); i += 1; } } else { // 剩余不足3位,直接复制剩下的位 // 此时,我们只需要复制第i位(因为剩余可能1位或2位,我们逐位复制) unsigned long bit = (input_int >> (total_bits - 1 - i)) & 0x1; result |= (bit << (total_bits - 1 - i)); i += 1; } } return result; } 但是,这里有一个问题:在设置剩余位的时候,我们也是逐位复制的,所以可以统一处理:当不足三位时,我们按一位处理(即进入else分支,然后逐位复制)。 但是,我们也可以将剩余不足三位的部分用另一个循环处理,但这里已经统一在while循环中处理了。 注意:在设置一位时,我们使用了: bit = (input_int >> (total_bits-1-i)) & 0x1; result |= (bit << (total_bits-1-i)); 而在取三位时,我们设置三位时,也是用: result |= (0x3ULL << (total_bits-3-i)); 这里要注意:0x3是3位,左移(total_bits-3-i)位,相当于将这三位放在从i开始的位置(即第i位到第i+2位)。 另外,在取三位时,我们通过移位操作取出了从i开始的三位,但是在设置时,我们直接设置了三位,这没有问题。 但是,在取一位时,我们并没有使用前面取出的temp,而是重新从input_int中取位?这样也可以,但为了效率,我们可以使用temp中的最高位(即我们之前取三位时已经包含了,所以可以复用)。 所以,在else分支(即不足三位时)我们重新取位,而在前面的else分支中我们使用了temp的最高位。 然而,在剩余不足三位时,我们不能取三位,所以只能重新取位(因为此时i>total_bits-3,我们无法取三位)。 但是,我们可以优化:在进入循环时,如果剩余不足三位,我们就直接复制剩余所有位。但是剩余位可能是1位或2位,我们这里用逐位复制。 测试:用例子101010(6位): 总位数total_bits=6。 i=0: 取三位:移位:total_bits-3-i=3,所以input_int右移3位:101010>>3=000101(二进制),然后&0x7=101(二进制),即5。匹配,所以设置0x3<<3:0x3<<3=011000,然后result=011000,i=3。 i=3: 此时剩余3位(i=3,total_bits-3=3,所以i<=3,进入if),取三位:移位:total_bits-3-i=0,所以input_int右移0位,然后&0x7=010(二进制),即2。不等于5,所以取最高位(0),然后设置第3位(即从0开始,第3位是第4位?注意:我们的位序是从0(最高位)到5(最低位))。 这里注意:我们的位序:第0位(最高位)对应权重5(即2^5),第1位对应2^4,第2位对应2^3,第3位对应2^2,第4位对应2^1,第5位对应2^0。 当i=3时,我们取的三位是第3,4,5位:因为total_bits-3-i=0,所以右移0位,然后取低三位,就是输入的低三位(010)。然后,我们取最高位(即第3位)是0,所以设置第3位:即设置result的第3位(即权重为2^2的位置)为0。但是,注意:result现在为011000(二进制),然后我们设置第3位(即从最高位0开始,第3位是第4位?)不对。 实际上,我们设置一位时,是设置在第total_bits-1-i位(即6-1-3=2,所以是左移2位?)。注意:result的位权重:最高位是5(即左移5位),最低位是0(左移0位)。所以,当i=3时,我们设置的是第3位(即从最高位开始数第3位,实际上是第3个位置,权重为6-1-3=2,所以左移2位)为0。所以,result还是011000(因为第3位已经是0了,而且我们设置0,所以不变)。 然后i=4,此时剩余2位,进入else分支:取第4位(即i=4):移位:6-1-4=1,所以input_int右移1位:101010>>1=010101(二进制),然后取最低位(&1)为1,然后设置第4位(左移6-1-4=1位)为1,即设置1<<1,所以result=011000 | 000010 = 011010。 然后i=5,取第5位:移位6-1-5=0,取最低位0,设置0<<0(即0),所以result不变。 最终result=011010,即0x1A,正确。 但是,注意:在设置一位时,我们使用: bit = (input_int >> (total_bits-1-i)) & 0x1; result |= (bit << (total_bits-1-i)); 这样,当i=3时,total_bits-1-i=2,所以移位2位,然后取最低位,然后左移2位,这样设置的是第3位(从0开始计数,即第3位是第4个位置?不对,因为最高位是0,然后依次是1,2,...,所以第0位是最高位,第1位是次高位,...,第5位是最低位。所以,当i=3时,实际上是在设置第3位(即从最高位开始数第4位?因为0,1,2,3,所以第3位是第4个位置?)不对,实际上,位的位置和权重对应:第0位对应权重total_bits-1,第1位对应total_bits-2,...,第i位对应权重total_bits-1-i。 所以,我们设置第i位时,就是左移(total_bits-1-i)位。这样,第0位(最高位)左移(total_bits-1)位,第1位左移(total_bits-2)位,...,第5位(最低位)左移0位。所以正确。 但是,在设置三位时,我们设置的是从i开始的三位:即第i位(最高位)、i+1位、i+2位(最低位)。所以,这三位在result中占据的位置是:权重从(total_bits-1-i)(total_bits-1-i-2)。所以,我们将0x3(二进制011)左移(total_bits-3-i)位,这样,0x3的最高位(0)就会在(total_bits-1-i)的位置,次高位(1)在(total_bits-2-i)的位置,最低位(1)在(total_bits-3-i)的位置。所以正确。 因此,代码可以这样。 但是,注意:在取三位时,我们使用了: temp = (input_int >> (total_bits-3-i)) & 0x7; 这个移位操作,当total_bits-3-i为负数时,移位操作是未定义的。所以,我们要确保total_bits-3-i>=0。而我们在if条件中已经保证了i<=total_bits-3,所以total_bits-3-i>=0。 另外,我们使用无符号移位,所以不会出现符号位问题。 但是,在C语言中,移位超过或等于该类型的位数是未定义的。所以,当total_bits-3-i等于或大于unsigned long的位数时,会有问题。但total_bits-3-i最大为total_bits-3(当i=0),而total_bits就是unsigned long的位数,所以total_bits-3-i的范围是0到total_bits-3,而移位范围是0到total_bits-3,所以不会超过或等于total_bits(因为total_bits-3<total_bits,因为total_bits>=3)。所以安全。 但是,当total_bits=3时,i=0,total_bits-3-i=0,所以移位0位,没问题。 另外,我们使用0x3ULL,确保在64位系统中,左移不会溢出。 但是,在设置三位时,我们使用了按位或,所以如果之前已经设置过某些位,这里会覆盖吗?不会,因为result初始为0,而且每个位只被设置一次(因为i是递增的,不会重复设置同一个位)。 所以,我们编代码: 注意:total_bits-3-i可能很大,所以使用无符号长整型移位。 但是,在移位时,如果移位超过63位(在64位系统中)是未定义的,但我们的移位量total_bits-3-i最大为total_bits-3,而total_bits是64,所以最大61,小于64,所以安全。 代码实现: 我们使用sizeof(unsigned long)*8计算总位数。 但是,不同的平台(32位或64位)中,unsigned long的位数不同。所以我们的代码是可移植的。 测试:输入0xAAAAAAAA(32位),二进制为:10101010...10(共16个10) 我们期望:将每个101替换为011,但是注意:101010...,从高位开始: 前三位:101 -> 替换为011,然后跳过三位,接着三位是010(不替换),然后下一位是1,然后下三位是010(不替换)?不对,因为替换后跳过三位,所以下一个三位是从第3位开始(0开始计数): 第3,4,5位:010 -> 不替换,然后移动一位到第4位:取第4,5,6位:101(因为第4位是1,第5位是0,第6位是1)-> 替换为011,然后跳过三位,到第7位,依此类推。 所以,最终结果应该是:011 010 011 010 ... 即:011010011010...,所以每6位重复:011010(二进制),即0x6A(十六进制)重复。 因此,32位0xAAAAAAAA(10101010...)转换后应为0x6A6A6A6A。 我们可以用这个测试。 但是,我们也可以测试一个小的数:比如8位:10101010 -> 替换:前三位101->011,然后跳过,接着三位010->不替换(然后移动一位到第3位,取第3,4,5位:101->替换为011,然后跳过,接着第6,7位(不足三位)直接复制:10。所以结果为:01101110,即0x6E。 所以,我们编代码并测试。 但是,注意:在32位系统中,unsigned long是32位,在64位系统中是64位。我们这里不指定,使用sizeof。 代码: 注意:移位操作时,如果移位位数等于或大于该类型的位数,行为未定义。所以,我们确保移位位数在0到总位数-1之间(在取一位时,移位位数total_bits-1-i,当i=0时最大为total_bits-1,小于总位数,所以安全)。 编函数: 我们将总位数计算放在函数开头。 另外,注意:当输入为0时,应该返回0。 我们开始编代码:</think>以下是一个用C语言实现的`pattern_replace`函数,该函数从高位到低位扫描输入的二进制位,将连续的"101"替换为"011",并跳过已替换的位继续处理: ```c #include <stddef.h> // 用于size_t unsigned long pattern_replace(unsigned long input_int) { // 计算无符号长整型的位数(通常为32或64位) const size_t total_bits = sizeof(unsigned long) * 8; unsigned long result = 0; // 存储最终结果 size_t i = 0; // 当前扫描位置(从最高位开始) while (i < total_bits) { // 检查剩余位数是否足够3位 if (i <= total_bits - 3) { // 提取从位置i开始的连续3位 unsigned long three_bits = (input_int >> (total_bits - 3 - i)) & 0x7; if (three_bits == 0x5) { // 二进制101=0x5 // 将011入结果的对应位置 result |= (0x3ULL << (total_bits - 3 - i)); i += 3; // 跳过已处理的3位 } else { // 保留当前最高位(three_bits的最高位) unsigned long bit = (three_bits >> 2) & 0x1; result |= (bit << (total_bits - 1 - i)); i += 1; // 移动到下一位 } } else { // 处理剩余不足3位的部分 unsigned long bit = (input_int >> (total_bits - 1 - i)) & 0x1; result |= (bit << (total_bits - 1 - i)); i += 1; } } return result; } ``` ### 函数说明 1. **输入输出**: - 输入:`unsigned long input_int`(待处理的二进制数据) - 输出:`unsigned long`(替换后的结果) 2. **核心逻辑**: - 从最高位向最低位扫描,每次检查连续的3位 - 当检测到`101`时: - 在结果中相同位置入`011` - 跳过这3位,继续扫描后续位 - 未检测到`101`时: - 保留当前最高位 - 移动到下一位继续扫描 - 剩余不足3位时直接复制原始位 3. **位操作关键点**: - `(input_int >> (total_bits - 3 - i)) & 0x7`:提取从位置`i`开始的3位 - `0x3ULL << (total_bits - 3 - i)`:将`011`入结果的对应位置 - `bit << (total_bits - 1 - i)`:复制单个位到结果 ### 示例调用 ```c int main() { // 测试: 101010(二进制) -> 011010(二进制) unsigned long input = 0x2A; // 0b101010 = 42 unsigned long output = pattern_replace(input); printf("Input: 0x%lX\nOutput: 0x%lX\n", input, output); // 输出: Input: 0x2A, Output: 0x1A (0b011010=26) return 0; } ``` ### 性能说明 - **时间复杂度**:$O(n)$,其中$n$为二进制位数 - **空间复杂度**:$O(1)$,仅使用固定大小的变量 - 优化点:使用并行位操作可加速大规模数据处理(如SIMD指令)[^1] ### 注意事项 1. 大端序/小端序不影响结果(纯位运算操作) 2. 适用于任意位宽(32/64位系统通用) 3. 替换具有**非重叠性**:已替换的位不会参与后续匹配
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值