簡體   English   中英

運行一段存儲在Java字符串中的C代碼

[英]Running a piece of C code stored in a Java String

我這里有一個相當有趣的場景。 假設我在Java String中存儲了一段C代碼。 我需要在自己的Java程序中運行此代碼。

情況1

class Main{
      public static void main(String[] args) {
           String cCode  = "printf(\"Hello World\n\");"
            // I need to run the cCode here.
            // We are allowed to  call a method with params.
       }
}

我認為我應該做的是。

  1. 在Main中創建一個本機字段
  2. 將sCode寫入文件
  3. 從Java執行shell命令來編譯c代碼。
  4. 從Java調用本機方法

情況二

我正在考慮執行上述過程,因為如果源代碼是預定義的,我知道如何使用JNI進行此操作。

 class Main{

      static {
        System.loadLibrary("Main"); // Load native library at runtime
      }

      private native void sayHello();

      public static void main(String[] args) {
        new Main().sayHello();
      }

    }

如果是預先編寫的C代碼。 我們要做的是。

  1. 使用javac Main.java編譯Java類
  2. 生成C lib的標頭。 javah -jni Main
  3. 通過編寫C代碼來完成Main.c
  4. 使用gcc -share -I/path/to/jni -I/path/to/jni_md -o Main.so編譯C代碼
  5. 運行主。 java Main

誰能告訴我我走的路是否正確(在情況1中 )? 還是有更好的方法呢?

**注意:這里的關鍵是,我只可以編譯一次Java代碼。 (開頭)。**

編輯:檢查完@Dúthomhas的評論和答案后,我想我應該再解釋一件事。 我之所以這樣做是為了進行機器學習項目。 已經確定數值計算部分具有瓶頸,並且使用C作為上述方法值得嘗試。 因此,安全性目前尚無法解決。 我們只需要做一個實驗。

非答案答案: 不要那樣做。

由於幾個原因,您要執行的操作是一個壞主意,其中兩個主要原因是:

  • 它可能會(嚴重)打開安全漏洞
  • 實施成本可能超過收益

要求嵌入一種完全不同的語言意味着添加和鏈接一個庫以及大量用於同步該庫的代碼,以及執行靜態分析和對代碼進行沙箱處理的代碼。 換句話說,您正在要求在現有語言的基礎上實現整個語言。

可以爭論的是,無論如何,C都是基礎系統,甚至可以在其上實現JVM(通常是在其上),但這並不是重點。 問題不在於C庫,而是C編譯器/解釋器 ,就簡單的解釋型編程語言而言,這是一個相當復雜的代碼庫。

建議:使用Java

ToolProvider類是專門為向您提供Java代碼的動態編譯而設計的。 看一看。

確保使用SecurityManager類將代碼正確沙箱化。 (並且,如果可能,請在單獨的受限制的JVM中運行它。)

建議:使用JavaScript / ECMAScript

ScriptEngine類正是為此目的而設計的。 再次,谷歌周圍的例子。 同樣,不要忘記安全性。

建議:使用現有的庫

但是我真的想要/必須使用C

唉。 可以使用C,但只有非常困難。 Google圍繞着“嵌入式C解釋器”,用於小型C解釋器,您也許可以將其集成到您的源代碼中。 (祝您好運!)

讓我澄清一下您的兩個案例

情況1指的是C 程序無法運行。 這不是大多數人認為的“從Java調用本機方法” 您不能在Main中創建本機字段。 實際上,Java沒有本地字段,只有本地方法。 但是在案例1中 ,您也不使用本機方法。 您可以編譯和運行任何用C或任何其他語言編寫的程序(前提是運行時環境中提供了編譯器)。 為此,您可以使用Shell命令( Runtime.exec() )來編譯程序並運行它。 可以按照Runtime.exec()指定在命令行上傳遞C程序的參數。 它可以通過您選擇的任何IPC與Java進程進行通信。 通常,我們僅使用管道讀取子進程的標准輸出。

案例2使用JNI(Java本機接口)在進程內運行本機代碼。 您在此處描述的流程是正確的,但是您可以對其進行修改以使用在運行時構建的共享庫。 首先,刪除本機方法,並將loadLibrary()移至單獨的類。 確保僅在您的Main類運行gcc -o libMain.so命令(使用與案例1相同的Runtime.exec()之后,類加載器才加載此類。 這樣,靜態構造函數將加載新構建的庫。

在這兩種情況下,您都不需要重新編譯Java。 您不需要運行javah來構建libMain.so這只是一個方便的步驟,可以確保C頭與Java類同步。 但是在您的情況下,Java類不會更改-因此,本機方法簽名也不會更改。

請注意, 情況1比較容易,尤其是在必須運行其他編譯后的C'字符串'的情況下,但是如果必須多次調用本機方法, 情況2可能會提供更好的性能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM