Java에서 정수 바이트 교환

Sep 14 2020

나는 기대 하고 바이트를 바꾼 다음을 int반환하는 이 작은 함수를 가지고 있습니다 int.

public class Main {
    
    public static void main(String[] args) {
        int cafeBabe = 0xcafebabe;
        System.out.println(Integer.toHexString(cafeBabe));
        System.out.println(Integer.toHexString(byteSwap(cafeBabe)));
        System.out.println(Integer.toHexString(byteSwap(byteSwap(cafeBabe))));
    }
    
    public static int byteSwap(int a) {
        return ((a & 0xff000000) >>> 24) |
               ((a & 0x00ff0000) >>> 8)  |
               ((a & 0x0000ff00) << 8)   |
               ((a & 0x000000ff) << 24);
    }
}

기본적으로 우리는 엔디안 사이를 전환하고 있습니다. 이제 작업을 수행하는 더 나은 / 더 효율적인 방법이 있습니까?

답변

15 AJNeufeld Sep 14 2020 at 10:47

역사적 노트

OP의 질문에 대한 첫 번째 댓글 (답변이 게시되기 훨씬 전)은 직접 질문 한 질문이었고 매우 지적이있었습니다.

Integer.reverseBytes (cafeBabe)를 사용하지 않고 ?

질문은 두 가지였습니다.

  1. 기본 제공 방법이 존재하며이를 수행하는 가장 최적의 방법 일 가능성이 높다는 OP를 지적하십시오.
  2. 그들이 바퀴 를 재발 명 하려고하는지 물어보세요 .

해당 댓글 / 질문이 삭제되었습니다. OP가 응답하면 응답도 삭제되어 본 적이 없습니다.

이 답변은 OP reinvent-the-wheel을 옹호하지 않습니다 . Java JVM / JIT는 @HotSpotIntrinsicCandidate최종 사용자가 반드시 사용할 수없는 내부 기능 (예 :)을 사용하여 작업을 수행하는 가장 효율적인 방법을 구현할 것 입니다.

바퀴의 재발 명

public static int byteSwap(int a) {
    return ((a & 0xff000000) >>> 24) |
           ((a & 0x00ff0000) >>> 8)  |
           ((a & 0x0000ff00) << 8)   |
           ((a & 0x000000ff) << 24);
}

이 함수는 6 개의 고유 한 상수, 4 개의 AND 연산, 4 개의 시프트 및 3 개의 OR 연산을 사용합니다.

의 AND 연산으로 소용이 없다 ((a & 0xff000000) >>> 24)또는 ((a & 0x000000ff) << 24)마스킹되는 24 비트가 바로 어차피 시프트 보낸. 이렇게하면 상수 2 개와 AND 연산 2 개가 제거되어 코드가 다음과 같이 줄어 듭니다.

public static int byteSwap(int a) {
    return (a >>> 24)               |
           ((a & 0x00ff0000) >>> 8) |
           ((a & 0x0000ff00) << 8)  |
           (a << 24);
}

두 번째 작업의 순서를 재 작업하여 다른 상수 인을 제거 0x00ff0000하고 대신 0xff00상수 를 재사용 할 수 있습니다. 이렇게하면 세 번째 비트 마스크 상수가로드되지 않으므로 추가 JVM 바이트 코드 명령이 절약됩니다.

public static int byteSwap(int a) {
    return (a >>> 24)           |
           ((a >>> 8) & 0xff00) |
           ((a & 0xff00) << 8)  |
           (a << 24);
}

이 재 작업 된 버전은 Integer.reverseBytes()시스템 라이브러리 의 내장 코드 와 매우 유사합니다 .

@HotSpotIntrinsicCandidate
public static int reverseBytes(int i) {
    return (i << 24)            |
           ((i & 0xff00) << 8)  |
           ((i >>> 8) & 0xff00) |
           (i >>> 24);
}

주문의 차이가 추가 속도를 얻는 지 여부는 모르겠지만 (도넛에 대한 달러) @HotSpotIntrinsicCandidate주석이 아마도 가능할 것이므로 내장 기능을 사용하십시오.

6 Bobby Sep 14 2020 at 03:25

읽기 쉽고 좋아합니다.


개인적으로 저는 운영자를 새로운 라인에 유지하는 것을 선호하므로 라인이 어떻게 함께 속하는지 쉽게 확인할 수 있습니다.

return ((a & 0xff000000) >>> 24)
     | ((a & 0x00ff0000) >>> 8)
     | ((a & 0x0000ff00) << 8)
     | ((a & 0x000000ff) << 24);

서식 규칙을 따릅니다.


패턴을 더 잘 보이게 만들기 위해 첫 번째와 마지막 바이트를 서로 아래에 놓을 수 있습니다.

return ((a & 0xff000000) >>> 24)
     | ((a & 0x000000ff) << 24)
     | ((a & 0x00ff0000) >>> 8)
     | ((a & 0x0000ff00) << 8);

이렇게하면 마스크에서 패턴이 제거되지만 바이트가 이동하는 방식을 쉽게 추론 할 수 있습니다.


당신은 또한을 변환 할 수 intA를 byte(A의 도움으로 예를 들어 배열 ByteBuffer), 그것을 다시 변환하기 전에 해당 배열을 역. 그러나 효율성에 관한 한, 기본적으로 byte어레이 에 대한 모든 작업 이 동일한 작업을 수행해야하기 때문에 최소 작업 을 수행해야한다고 생각합니다.


이미 지적했듯이 Integer.reverseBytes(int)1.5부터 사용 가능한 것이 이미 있습니다.