如何纠正以下有关匹配位模式的代码?

时间:2016-07-17 06:40:40

标签: c function bits

我的任务是编写一个名为bitpatSearch()的函数,该函数在unsigned int内查找指定的位模式。该函数应该有3个参数:bitpatSearch(source, pattern, n)。它应该在整数source中搜索n最右边的pattern位,并输出模式开始的位数(对于32位整数,假设为0到31位排序)如果没有匹配,则匹配并-1

虽然练习建议从最左边的位进行搜索,但我的代码会从最右边的位置进行搜索,因为我认为它会更容易(因为我可以使用1进行AND值。)但是,有些东西是错误的,并且我怀疑return语句背后的算法可能是一个问题,但无法弄明白。

程序似乎总是让位置错误,但总是正确地告诉我是否匹配。

#include <stdio.h>

int bitpatSearch(unsigned int source, unsigned int pattern, int n){

unsigned int count, x, sourceCopy;

for(count = 0; count <= 32; ++count){ //loop for all possible shifts for a 32 bit integer

   x = 0; 

   sourceCopy = source >> count;

   while(((sourceCopy & 1) == (pattern & 1)) && (x != n)){

      sourceCopy >>= 1;

      pattern >>= 1;

      ++x;

      }

   if(x == n) //then there is a match

   return 32 - (count + n); // I think the problem is here, with basic arithmetic

}

return -1;

}

4 个答案:

答案 0 :(得分:2)

在内部while循环中,通过在匹配位时将其移位来部分销毁pattern。因此,如果您获得部分匹配,则pattern将不再为后续搜索保留正确的值。代码出错的一个例子是bitpatSearch(0xf0f, 0xff, 8)。您的代码在第12位找到匹配项,但在任何地方都没有匹配项。

我会写这样的代码:

#include <limits.h>

#define INT_BITS (CHAR_BIT * sizeof(unsigned))

int bitpatSearch(unsigned int source, unsigned int pattern, int n){
    if (n == 0) return 0;
    if (n > INT_BITS) return -1;
    if (n == INT_BITS) return source == pattern ? 0 : -1;
    pattern &= (1u << n) - 1;
    for (int i = 0; i <= INT_BITS - n; i++) {
        if (((source >> i) & ((1u << n) - 1)) == pattern) {
            return i;
        }
    }
    return -1;
}

与您的代码不同,它会尝试在pattern中一次性匹配source处的给定移位值的int的整体,并且是可移植的,因为它不会假设if (n == INT_BITS) return source == pattern ? 0 : -1;是一个特定的大小。

代码努力避免未定义的行为;特别是避免按INT_BITS或更多移位。例如,在构造掩码(1u << n) - 1时,必须使用案例#include <stdio.h> int main(int argc, char **argv) { struct { unsigned source, pattern; int n; int want; } test_cases[] = { { 0x0000000fu, 0xf, 4, 0 }, { 0x0000000fu, 0xf, 2, 0 }, { 0xf0000000u, 0xf, 4, 28 }, { 0xf0000000u, 0xf, 2, 28 }, { 0x01000000u, 0x1, 4, 24 }, { 0x80000000u, 0x1, 1, 31 }, { 1u << (INT_BITS - 1), 0x1, 2, -1 }, { 0xffffffffu, 0x6, 3, -1 }, { 0x777u, 0x77, 12, 4 }, { 0x1234abcdu, 0x1234abcdu, 32, 0 }, { 0x1234abcdu, 0x1234abcdu, 33, -1 }, { 0x1234abcdu, 0x42u, 0, 0 }, { 0xf0f, 0xff, 8, -1}, }; int failed = 0; for (int i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) { unsigned source = test_cases[i].source; unsigned pattern = test_cases[i].pattern; int n = test_cases[i].n; int want = test_cases[i].want; int got = bitpatSearch(source, pattern, n); if (got != want) { printf("bitpatSearch(0x%x, 0x%x, %d) = %d, want %d\n", source, pattern, n, got, want); failed = 1; } } return failed ? 1 : 0; } 来避免非法移位。

这是代码的一些简单的单元测试。一些测试用例假设是32位int,因为我太懒了,不能使它们可移植。

{{1}}

答案 1 :(得分:2)

您需要创建pattern的副本,因为每次进入while循环时,您都会更改pattern的值。因此,下次进入while循环时,您将与错误的模式进行比较。

 #include <stdio.h>

int bitpatSearch(unsigned int source, unsigned int pattern, int n){

unsigned int count, x, sourceCopy,patternCopy;

for(count = 0; count <= 32; ++count){ //loop for all possible shifts for a 32 bit integer

   x = 0;

   sourceCopy = source >> count;
   patternCopy=pattern;

   while(((sourceCopy & 1) == (patternCopy & 1)) && (x < n)){


      sourceCopy >>= 1;

      patternCopy >>= 1;

      ++x;
      }

   if(x == n) //then there is a match

   return 32 - (count + n); // I think the problem is here, with basic arithmetic

}

return -1;

}
int main()
{
    printf("%d",bitpatSearch(243,9,4));
    return 0;
}

答案 2 :(得分:1)

您不能将32位unsigned int移位32,它未定义。将循环更改为在32之前停止:

for (count = 0; count < 32; ++count)

或者更好,让它循环超过系统类型的大小,可能与32不同:

#include <limits.h>

...

for (count = 0; count < sizeof(source) * CHAR_BIT; ++count)

关于你的算法,如果你应该从最重要的位搜索,那就去做吧!否则,如果模式出现多次,您可能找不到预期的位置。

请注意,在没有编号系统的精确定义的情况下谈论位数是非常困惑的:最左边(最重要)位或最右边(最不重要)位是位0吗?在C中,通常对从最低有效位到最高有效位的位进行编号,因为这与移位运算符一致(位n具有值1U << n),但有些人习惯于编号从左到右的位,完全相反的惯例。

答案 3 :(得分:1)

请注意,位编号通常是从右到左,最右边的位是位0。

您的代码非常复杂。嵌套循环不是必需的。这是一个简单的解决方案(模式搜索从右到左):

(编辑:代码现在包括Paul Hankin和underscore_d建议的改进。)

#include <stdio.h>
#include <limits.h>

#define NO_MATCH -1
#define ARGUMENT_ERROR -2

#define DEBUG

int bitpatSearch(unsigned int source, unsigned int pattern, unsigned int n) {
    unsigned int mask;
    unsigned int tmp;
    int i;

    /********************************************************************
     * Three trivial cases:
     * 
     * (a) If n = 0, then every pattern is a match; so return 0
     *     (match at position 0).
     * (b) If n = CHAR_BIT * sizeof(source), then there is a match at
     *     position 0 if source equals pattern and no match otherwise.
     * (c) If n > CHAR_BIT * sizeof(source), it makes no sence to test
     *     for matching patterns, because we don't know the
     *     n - CHAR_BIT * sizeof(source) most significant bits.
     *******************************************************************/
    if (n == 0)
    {
        return 0;
    }
    if (n == CHAR_BIT * sizeof(source)) {
        if (source == pattern) {
            return 0;
        }
        return NO_MATCH;
    }
    if (n > CHAR_BIT * sizeof(source)) {
        return ARGUMENT_ERROR;
    }

    mask = ~((~0u) << n);
    pattern &= mask;

    #ifdef DEBUG
    printf("mask    = 0x%08x\n", mask);
    printf("pattern = 0x%08x\n", pattern);
    #endif

    for (i = 0; i <= CHAR_BIT * sizeof(source) - n; i++) {
        tmp = (source >> i) & mask;
        #ifdef DEBUG
        printf("tmp     = 0x%08x at position %2i:\n", tmp, i);
        #endif
        if (tmp == pattern) {
            #ifdef DEBUG
            printf("Match at position %2i!\n", i);
            #endif
            return i;
        }
    }

    return NO_MATCH;
}

int main() {
    int result;

    /*
    dec 243 = bin 11110011
    dec   9 = bin    1001
                        ^ match at position 1
    */

    result = bitpatSearch(243, 9, 4);
    printf("Result = %i\n", result);

    return 0;
}