Java中的memcmp()等效函数是什么?

10

如果我有两个byte[]数组,是否有内置函数可以像C语言的memcmp()一样进行比较?

6个回答

7

Memcmp函数返回一个int类型的值,如果s1的前n个字节小于s2的前n个字节,则返回小于零的值,如果相等,则返回零,如果大于,则返回大于零的值。而Equals函数则返回一个布尔值。这两个函数不同。此外,memcmp是将字节作为无符号字符进行比较。

我认为以下内容可以起到作用:

public int memcmp(byte b1[], byte b2[], int sz){
    for(int i = 0; i < sz; i++){
        if(b1[i] != b2[i]){
            if(b1[i] >= 0 && b2[i] >= 0)
                return b1[i] - b2[i];
            if(b1[i] < 0 && b2[i] >= 0)
                return 1;
            if(b2[i] < 0 && b1[i] >= 0)
                return -1;
            if(b1[i] < 0 && b2[i] < 0){
                byte x1 = (byte) (256 + b1[i]);
                byte x2 = (byte) (256 + b2[i]);
                return x1 - x2;
            }
        }
    }
    return 0;
}

事实上,二进制补码部分并非必需:
public static int memcmp(byte b1[], byte b2[], int sz){
    for(int i = 0; i < sz; i++){
        if(b1[i] != b2[i]){
            if((b1[i] >= 0 && b2[i] >= 0)||(b1[i] < 0 && b2[i] < 0))
                return b1[i] - b2[i];
            if(b1[i] < 0 && b2[i] >= 0)
                return 1;
            if(b2[i] < 0 && b1[i] >=0)
                return -1;
        }
    }
    return 0;
}

返回值1和返回值-1不是颠倒了吗? - Chris Westin

4

有一个Arrays.equals()方法。

我不知道JVM实现是否会优化这个方法,如果硬件上存在相应的指令,但我对此表示怀疑。

另外,如果我记得我的C语言正确,strcmp函数可以比较到空终止符(使其对于C字符串很有用),而Arrays版本将比较整个数组,因为Java程序员很少使用空终止数组。如果您关心空终止符,您可以轻松地编写自己的函数。


我很好奇有人在Java中会将自己的数组置为空。 - matt b
我从未尝试过这样做,但我会猜想,也许如果在C中调用本地方法并使用缓冲区... - Uri
5
strcmp函数的起源是什么?这个问题是关于memcmp函数的,我在编辑历史中也看不到strcmp。 - laalto
1
从man页面中可以看到:“如果在s1的前n个字节中,第一个不匹配的字节小于s2中对应的字节,则返回一个小于零的整数;如果相等,则返回零;否则返回大于零的整数。” Arrays.equals()函数并没有给出哪个数组更大的指示。 - fbarber

4

2

Arrays.equals()方法很好用,但无法比较子范围。在这种情况下,可以使用Arrays.listOf().subList()方法,但对于像byte[]这样的原始类型则不适用。

实际上,并没有直接等价于memcmp()的方法。在这里有一篇讨论,就我所知,它至今仍处于同样的状态(15年了)。大多数“本地”实现可以通过java.nio.ByteBuffer(使用wrap()方法然后equals())来实现。但这需要写相当多的代码。

对于完全不了解此主题的人:memcmp()是以平台相关的方式实现的,非常高效,目前在Java中没有任何方法能够与之媲美。任何手动循环都远远落后于性能,至少因为索引范围检查。也许某一天,那些从嵌入式C / C++转来的人会对此感到满意 :-)


1
提到子范围时加1。在这种情况下,可以使用Arrays.copyOfRange()Arrays.equals(),但可能不太有效率。 - Ciro Santilli OurBigBook.com
1
Java语言版本9及以上的Arrays.equals()方法有一个带子范围签名的变体。 - foo

0

[Arrays.equals][1]

[1]:{{link1:http://java.sun.com/j2se/1.5.0/docs/api/java/util/Arrays.html#equals(byte[]}}, byte [])


0
在Java 8中,如果你愿意将字节视为无符号值,那么可以使用C/C++ memcmp实际执行的操作:
private static int memcmp(byte[] a, byte[] b, int sz) {
    for (int i = 0; i < sz; i++) {
        if (a[i] != b[i]) {
            return Byte.toUnsignedInt(a[i]) - Byte.toUnsignedInt(b[i]);
        }
    }
    return 0;
}

这就是C/C++的memcmp函数的功能。通常它是内部函数——这意味着高度优化,调用一些内联汇编来使用处理器指令。在我看来,Java提供类似的东西(当然包括子范围)已经是时候了。他们有system.arraycopy,那为什么没有System.bytearraycmp呢?当你需要比较字节数组的范围时,通常是因为你正在编写需要快速运行的代码。 - John Calcote

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接