반응형


어떤 API를 C에서 Java로 포팅중이다. 자바는 Call by value, Call by Ref.. 이다 마다... 에 따라서
여튼... Out Parameter를 어떻게 넘기냐라는 고민을 특히 C개발자분이라면 해보셨을 것 같다.
아마 이 페이지를 들어오신 분도 그런 분들이실테고,,,
앞서 포스팅 중인 저는 초보개발자이며, 단순 제 생각을 적었다는 것을 말씀드립니다.

구체적 예시는 'byte[]'를 함수내에서 받아오는 방법을 나열할 것 이고,
방법은 4가지로 나누었습니다. 그 방법에 들의 대한 키워드와 쏘스는 아래와 같습니다.
Application.java : Main함수
Interface.java : API

1. C style  

# Application.java
public class Application{
 public static void main(String[] argv) throws Exception
 {
  Interface api = new Interface();
 
  int nRet = -1;
  byte[] buffer = new byte[4096];
  byte[] len = new byte[4];

  byte[] ReturnData = null;
  nRet = api.GetMSG(buffer, len);  
  if(nRet != 0)
  {
   system.out.println("Error");   
  } 
  else
  {
   ReturnData = new byte[api.ByteToInt(len)];
   system.arraycopy(buffer, 0, ReturnData, 0, ReturnData.length);   
  } 
 } 
}
# Interface.java
public class Interface{
 public int GetMSG(byte[] buffer, byte[] len) throws Exception
 {
  String strTest = "Test Message";
  byte[] byTest = strTest.getBytes();
  
  if(byTest.length > buffer.length)
  {
   return -1; //버퍼크기가 작습니다.
  }
  System.arraycopy(IntToByte(byTest.length), 0, len, 0, 4);
  System.arraycopy(byTest, 0, buffer, 0, byTest.length);   
  return 0;
 } 
}
# IntToByte & ByteToInt

static public byte[] IntToByte(int nNum)
{
  byte[] abNum = new byte[4];
  abNum[3] = (byte) (nNum);
  abNum[2] = (byte) ((nNum >> 8));
  abNum[1] = (byte) ((nNum >> 16));
  abNum[0] = (byte) ((nNum >> 24));
  return abNum;
}
 
static public int ByteToInt(byte[] abNum)
{
  int datasize = 0;
  
        if (abNum.length == 4) {
            datasize =
                    (( (int) abNum[0] & 0xFF) << 24) +
                            ( (int) (abNum[1] & 0xFF) << 16) +
                            ( (int) (abNum[2] & 0xFF) << 8) +
                            ( (int) (abNum[3] & 0xFF) << 0);             
        } else {
            datasize =
                    ((abNum[0] & 0xFF) << 8) +
                            ((abNum[1] & 0xFF) << 0);
        }
        return datasize;       


2. Class

# Application.java
public class Application{
 public static void main(String[] argv) throws Exception
 {
  Interface api = new Interface();
 
  int nRet = -1;
  Data buffer = new Data(new byte[4096]);
  byte[] ReturnData = null;
  nRet = api.GetMSG(buffer);  
  if(nRet != 0)
  {
   system.out.println("Error");   
  } 
  else
  {
   ReturnData = buffer.getData();      
  } 
 } 
}

# Interface.java
public class Interface{
 public int GetMSG(Data buffer)
 {
  String strTest = "Test Message";
  byte[] byTest = strTest.getBytes();
  
  if(byTest.length > buffer.getLen())
  {
   return -1; //버퍼크기가 작습니다.
  }
  buffer.setData(byTest, byTest.length);
  return 0;
 } 
}


# Data Class

 public class Data{
 private byte[] abData = null;
 private int nLen = 0;
 
 public Data() {}
 public Data(byte[] InputData)
 {
  this.abData = new byte[InputData.length];
  this.nLen = InputData.length;
 } 
 
 public void SetData(byte[] InputData, int Len)
 {
  System.arraycopy(InputData, 0, this.abData, 0, Len);
  this.nLen = Len;
 }


 public byte[] GetData()
 {
  byte[] buffer = new byte[this.nLen];
  System.arraycopy(abData, 0, buffer, 0, this.nLen);
  return buffer;
 }
 
 public int GetLen()
 {
  return this.nLen;
 } 
}


3. Return


# Application.java
public class Application{
 public static void main(String[] argv) throws Exception
 {
  Interface api = new Interface();
 
  int nRet = -1;  
  byte[] ReturnData = null;
  try
  {
   ReturnData = api.GetMSG();  
  }
  catch(Exception e)
  {
   throw new Exception(e.getMessage());
  }   
 } 
}

# Interface.java
public class Interface{
 public byte[] GetMSG() throws Exception
 {
  nRet = -1;
  try
  {
   String strTest = "Test Message"; 
  }
  catch(Exception e)
  {   
   nRet = xxx;
   throw new Exception("ErrCode : " + nRet); //try에서 어떤작업에 대한 Error처리시
  }    
  return strTest.getBytes();
 } 
}


4. Get Function


# Application.java
public class Application{
 public static void main(String[] argv) throws Exception
 {
  Interface api = new Interface();
 
  int nRet = -1;
  Data buffer = new Data(new byte[4096]);
  byte[] ReturnData = null;
  nRet = api.GetMSG();  
  if(nRet != 0)
  {
   system.out.println("Error");   
  } 
  else
  {
   ReturnData = api.getOutParam("GetMSG");      
  
 } 
}

# Interface.java
public class Interface{
 byte[] m_byTest = null;
 public int GetMSG()
 {
  String strTest = "Test Message";
  byte[] byTest = strTest.getBytes();
  
  m_byTest = new byte[byTest.length];
  system.arraycopy(byTest, 0, m_byTest, 0, byTest.length);
  return 0;
 } 
 
 public byte[] getOutParam(String FuncName)
 {
  if(FuncName.equals("GetMSG")
   return m_byTest;
  
  return "잘못된 함수이름입니다.".getByte();
 }
}


5. ArrayList


# Application.java
public class Application{
 public static void main(String[] argv) throws Exception
 {
  Interface api = new Interface();
 
  int nRet = -1;  
  ArrayList<Object> arList = new ArrayList<Object>();
  try
  {
   arList = api.GetMSG();  
  }
  catch(Exception e)
  {
   throw new Exception(e.getMessage());
  } 
  byte[] output = null;
  if(arList.size() > 0)   output = (byte[])arList.get(0);

   
 } 
}


# Interface.java
public class Interface{
 public ArrayList<Object> GetMSG() throws Exception
 {
  nRet = -1;
  ArrayList<byte[]> outBuffer = new ArrayList<byte[]>();

  try
  {
   String strTest = "Test Message"; 
  }
  catch(Exception e)
  {   
   nRet = xxx;
   throw new Exception("ErrCode : " + nRet); //try에서 어떤작업에 대한 Error처리시
  }    
  outBuffer.add(0, strTest.getBytes());

  return outBuffer;
 } 
}






응용 프로그래머가 볼 때, 종합적으로 살펴서 비교하면 다음과 같습니다.

              버퍼할당  //  에러처리    //  추가작업  //  객체갯수
1. Cstyle   :    O      //  Err Code   // ByteToInt  //     3(Buffer, BufferLen, Output)
2. Class    :    O      //  Err Code   //   Class     //     2(Class, Output)
3. Return   :    X      //  Exception  //     X         //     1(Output)
4. GetFunc :    X      //  Err Code   // get func    //     1(Output)
5. ArrayList :   X      //  anyway  //    get        //     1(Output)
- 여기서 버퍼할당은 객체할당이 아닌 직접적 byte[xxx]를 말하는 것임.


1. C Style
null로 초기화를 한다던지가 아니고, 버퍼를 할당하는 이유는 당연히,
응용단에서 인스턴스화 하지 않으면, 함수를 수행하고 난 뒤에 바뀌는 것이 하나도 없기 때문이다.
하지만 정확히 공간을 어느정도 설정해야할지 모르기 때문에,
여유롭게 주는 것 이고, 길이값을 인티저 객체를 쓰는 방법도 있지만, 오로지 byte[]를 이용했다.
그래서 함수 수행 후, 그 길이만큼만 사용한다. 결론은 번거롭다. 자바스럽지 않다.
번외로, 큰 여유버퍼를 예를 들어서 4096을 계속 쓰면 낭비일 수도 있는데,
메모리의 지역성이 반면 높아져서 불규칙한 버퍼크기보단, 같은 버퍼크기가 더 낫다고도 한다.

2 Class
C 스타일과 비슷하다. C에서 구조체를 대신 사용한다고 생각하면 된다.
다만 응용단에서 볼 때, 작업량이 좀 줄어든다고 할 수 있다.

3. Return
제일 자바스럽다. Exception 기능도 살리고, 응용단이든 인터페이스단이든
모든 부분에서 라인수도 크게 줄어든다.
파라미터 2개이상을 Out 시켜야 한다면, 메세지를 만들고 파싱을 하는 작업을 따로 한다던지.
전용 Get함수를 만들던지 알아서 해결해야 한다. 5번 ArrayList를 활용해도 좋다.
단순 Text를 넘기다보니, Exception 처리에 대한 예제는 그냥 형식상으로 남겨두었다.

4. Get Func
이것 또한 자바스러운 방법 중에 하나이며, 에러코드와 Exception 처리 모두 가능하다.
라인 수 또한 줄어드는 편이다.
데이타를 받는 것은, 여러 API가 생성될 것을 생각하여
메쏘드에 함수이름을 인자로 받아, 경우에 따라서 다른 전역변수를 리턴하도록 하였다. 

컴파일을 해본 것은 아니니, 오타는 있을 수 있다.
하지만 방법론에 있어서 저 4가지방식으로 실제 해보았다.
필자의 팀장은 3번 방향으로 가길 추천하였다.

5. ArrayList
import java.util.ArrayList; 를 하여 ArrayList 인스턴스화 하여, 리턴값 받으면 된다.
자바스럽다. 자바독을 봐서, 용법에 대해서 조금 알아본 뒤에 적절하게 맞게 사용하길 추천,
호출해서 add 하고 리턴받으면, size 체크하여 get만 하면 문제없다.
3번처럼 Return형식과 비슷하다.

궁금한 것이 있다면, 댓글을 남겨주세요.
성심 성의 것 ,, 답이 아닌 제 생각을 달아드리리다....
얻어간 것이 있다면, 저 또한 감사합니다. 클릭클릭

반응형
Posted by Rainfly
l