2013-08-19 32 views
5

Trong tài liệu hướng dẫn của JNI chức năng FindClass tôi có thể đọc về lập luận tên:chuỗi JNI và chuỗi C

tên: một tên lớp đầy đủ (...) Các chuỗi được mã hóa trong sửa đổi UTF-8.

Theo tài liệu sửa đổi UTF-8 đã kết thúc với đôi '\ 0' chars:

các ký tự null (char) 0 được mã hóa bằng cách sử dụng định dạng hai byte chứ không phải là one- byte định dạng

Liệu nó có nghĩa rằng tôi nên gọi FindClass từ C theo cách này: FindClass("java/lang/String\0")

tức là với đôi '\ 0' ở cuối?

+2

Điều gì đã xảy ra khi bạn thử, nó có hoạt động hay không? – mah

+0

@mah Các câu hỏi hỏi "nên" không "có thể". Đó là về tính chính xác về kỹ thuật chứ không phải ["lập trình bằng sự trùng hợp."] (Http://pragprog.com/the-pragmatic-programmer/extracts/coincidence) Tất nhiên nó hoạt động nhưng điều đó không đúng. –

Trả lời

3

Bộ ký tự, mã hóa và chấm dứt là ba điều khác nhau. Rõ ràng, một mã hóa được thiết kế cho một bộ ký tự cụ thể nhưng một bộ ký tự có thể được mã hóa theo nhiều cách. Và, thường, một terminator (nếu được sử dụng) là một ký tự được mã hóa, nhưng với UTF-8 đã sửa đổi, đây không phải là trường hợp.

Java sử dụng bộ ký tự Unicode. Đối với chuỗi và kiểu char, nó sử dụng mã hóa UTF-16. Loại chuỗi được tính; Nó không sử dụng một terminator.

Trong C, các chuỗi đã chấm dứt là phổ biến, cũng như mã hóa một byte của các bộ ký tự khác nhau. Trình biên dịch C và C++ chấm dứt chuỗi ký tự bằng ký tự NUL. Trong bộ mã hóa ký tự đích của trình biên dịch, đây là một hoặc hai byte 0x00. Hầu như tất cả các bộ ký tự phổ biến và mã hóa của chúng đều có cùng biểu diễn byte cho các ký tự ASCII không kiểm soát . Điều này đúng với mã hóa UTF-8 của bộ ký tự Unicode. (Nhưng, lưu ý rằng không đúng đối với các ký tự nằm ngoài tập con giới hạn.)

Các nhà thiết kế JNI đã chọn sử dụng khả năng tương tác "giới hạn" này giữa các chuỗi C. Nhiều hàm JNI chấp nhận các chuỗi được sửa đổi UTF-8 0x00. Đây là những gì tương thích với những gì một trình biên dịch C sẽ sản xuất từ ​​một chuỗi ký tự trong mã nguồn, một lần nữa với điều kiện các ký tự được giới hạn ở các ký tự ASCII không kiểm soát . Điều này bao gồm trường hợp sử dụng viết gói Java & lớp, phương thức và chuỗi trường trong JNI. (Vâng, gần như: Java cho phép bất kỳ ký hiệu tiền tệ Unicode nào trong một mã định danh.)

Vì vậy, bạn có thể chuyển các chuỗi ký tự C thành hàm JNI theo kiểu WYSIWYG. Không cần phải thêm một terminator - trình biên dịch thực hiện điều đó. Trình biên dịch C sẽ mã hóa thêm các ký tự '\ 0' thành 0x00 để nó không gây hại gì nhưng không cần thiết.

Có một vài sửa đổi từ mã hóa UTF-8 chuẩn. Một là cho phép các hàm C mong đợi một terminator 0x00 để "xử lý" các chuỗi UTF-8 đã sửa đổi, ký tự NUL (U + 00000) được mã hóa để tránh 0x00, đây sẽ là tiêu chuẩn. Điều đó cho phép sửa đổi các chuỗi UTF-8 được đặt vào một bộ đệm với một terminator 0x00 vượt quá các byte của chuỗi được mã hóa ban đầu. Các sửa đổi khác là một chút bí truyền nhưng cả hai sửa đổi làm cho một chuỗi UTF-8 sửa đổi không tương thích với một hàm UTF-8 tuân thủ nghiêm ngặt.

Bạn không yêu cầu, nhưng có một cách sử dụng khác là 0x00 kết thúc, sửa đổi chuỗi UTF-8 trong JNI. Đó là với các chức năng GetStringUTFCharsNewStringUTF. (Tài liệu JNI không thực sự nói rằng GetStringUTFChars trả về chuỗi bị chấm dứt 0x00 nhưng không có triển khai JVM đã biết nào không. Kiểm tra tài liệu hoặc mã nguồn của trình cài đặt JVM của bạn.) Các chức năng này được thiết kế trên cùng cơ sở "khả năng tương tác". Tuy nhiên, các trường hợp sử dụng khác nhau, khiến chúng trở nên nguy hiểm. Chúng thường được sử dụng để truyền các chuỗi Java giữa các hàm C. Các chức năng C, nói chung, sẽ không có ý tưởng những gì sửa đổi UTF-8 là, hoặc có thể không phải là những gì UTF-8 hoặc Unicode được. Nó trực tiếp hơn nhiều khi sử dụng các lớp Java StringCharset để chuyển đổi sang và từ bộ ký tự và mã hóa mà các hàm C được thiết kế cho. Thông thường, đó là cài đặt hệ thống, cài đặt người dùng, cài đặt ứng dụng hoặc cài đặt chuỗi xác định chức năng C đang sử dụng. Lớp Java String cố gắng tuân thủ các cài đặt như vậy khi không đưa ra một mã hóa cụ thể cho một chuyển đổi. Tuy nhiên, có nhiều trường hợp, mã hóa mong muốn được cố định và có thể được xác định với mục đích rõ ràng.

3

Không, according to the first reference I found, nó có nghĩa là nó phải được mã hóa như thế này:

FindChar("java/lang/String\xc0\x80"); 
          ^
           | 
           | 
        This is not the shortest 
        way to encode the codepoint 
        U+0000, which is why it's 
        "modified" UTF-8. 

Lưu ý rằng điều này giả định rằng bạn đang thực sự tìm kiếm tên lớp có đuôi U + 0000, mà là khá khó xảy ra. Chuỗi C nên được chấm dứt giống như bình thường, với một đơn 0-byte như bạn nhận được từ chỉ:

FindChar("java/lang/String"); 

Mã hóa 2-byte đặc biệt của U + 0000 được cung cấp bởi Modified UTF-8 chỉ quan trọng nếu bạn muốn để đặt U + 0000 vào một chuỗi, và vẫn có thể phân biệt nó với dấu kết thúc C.

3

Không, bạn không mã hóa kết thúc bằng không, nó không phải là một phần của tên lớp.