특정 유니 코드 문자가 포함 된 주석에서 Java 코드를 실행하는 이유

java unicode comments


다음 코드는 "Hello World!"출력을 생성합니다. (실제로 시도하십시오).

public static void main(String... args) {

   // The comment below is not a typo.
   // \u000d System.out.println("Hello World!");
}

그 이유는 Java 컴파일러가 유니 코드 문자 \u000d 를 새 줄로 구문 분석하여 다음 과 같이 변환하기 때문입니다.

public static void main(String... args) {

   // The comment below is not a typo.
   //
   System.out.println("Hello World!");
}

따라서 주석이 "실행"됩니다.

이것은 악의적 인 코드 또는 악의적 인 프로그래머가 생각할 수있는 것을 "숨길"데 사용될 수 있기 때문에 왜 주석에 허용 됩니까?

Java 스펙에서 이것이 허용되는 이유는 무엇입니까?




Answer 1 aioobe


유니 코드 디코딩은 다른 어휘 변환 전에 발생합니다. 이것의 주요 이점은 ASCII와 다른 인코딩 사이를왔다 갔다하는 것이 사소한 것입니다. 주석이 어디서 시작하고 끝나는 지 알아낼 필요조차 없습니다!

JLS 섹션 3.3에 명시된 바와 같이 ASCII 기반 도구는 소스 파일을 처리 할 수 ​​있습니다.

[...] Java 프로그래밍 언어는 프로그램을 ASCII 기반 도구로 처리 할 수있는 형식으로 변경하는 유니 코드로 작성된 프로그램을 ASCII로 변환하는 표준 방법을 지정합니다. [...]

이것은 항상 Java 플랫폼의 핵심 목표였던 플랫폼 독립성 (지원되는 문자 세트의 독립성)을 근본적으로 보증합니다.

파일의 어느 곳에서나 유니 코드 문자를 쓸 수 있다는 것은 깔끔한 기능이며, 특히 비 라틴 언어로 코드를 문서화 할 때 주석에서 중요합니다. 그것이 미묘한 방식으로 의미론을 방해 할 수 있다는 사실은 (불행한) 부작용입니다.

이 주제에는 많은 문제가 있으며 Joshua Bloch와 Neal Gafter의 Java Puzzlers 는 다음 변형을 포함했습니다.

이것은 합법적 인 Java 프로그램입니까? 그렇다면 무엇을 인쇄합니까?

\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020\u0020
\u0063\u006c\u0061\u0073\u0073\u0020\u0055\u0067\u006c\u0079
\u007b\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020
\u0020\u0020\u0020\u0020\u0073\u0074\u0061\u0074\u0069\u0063
\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028
\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0020
\u0020\u0020\u0020\u0020\u0061\u0072\u0067\u0073\u0029\u007b
\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074
\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0020
\u0022\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u0022\u002b
\u0022\u006f\u0072\u006c\u0064\u0022\u0029\u003b\u007d\u007d

(이 프로그램은 일반 "Hello World"프로그램으로 판명되었습니다.)

퍼즐 러에 대한 해결책에서 그들은 다음을 지적합니다.

더 진지하게,이 퍼즐은 이전 세 가지 교훈을 강화하는 데 도움이됩니다 . 유니 코드 이스케이프는 다른 방식으로 표현할 수없는 문자를 프로그램에 삽입해야 할 때 필수적입니다. 다른 모든 경우에는 피하십시오.


출처 : 자바 : 주석에서 코드를 실행하고 있습니까?!




Answer 2 Holger


이것이 아직 다루어지지 않았으므로 여기에 설명, 왜 다른 소스 코드 처리 전에 유니 코드 이스케이프 변환이 발생합니까?

그 뒤에 아이디어는 다른 문자 인코딩간에 Java 소스 코드를 무손실로 번역 할 수 있다는 것입니다. 오늘날 유니 코드 지원은 널리 보급되어 있지만 문제처럼 보이지는 않지만 서구의 개발자가 아시아 문자를 포함하는 아시아 동료로부터 소스 코드를 수신하는 것은 쉽지 않았습니다. (컴파일 및 테스트 포함) 결과를 손상시키지 않고 결과를 다시 보냅니다.

따라서 Java 소스 코드는 모든 인코딩으로 작성 될 수 있으며 식별자, 문자 및 String 리터럴 및 주석 내의 광범위한 문자를 허용합니다 . 그런 다음 무손실로 전송하기 위해 대상 인코딩에서 지원하지 않는 모든 문자는 유니 코드 이스케이프로 대체됩니다.

이것은 뒤집을 수있는 프로세스이며 흥미로운 점은 변환 규칙이 종속되지 않기 때문에 Java 소스 코드 구문에 대해 아무것도 알 필요가없는 도구로 변환을 수행 할 수 있다는 것입니다. 이것은 컴파일러 내부의 실제 유니 코드 문자로의 변환으로 Java 소스 코드 구문과 독립적으로 발생합니다. 소스 코드의 의미를 변경하지 않고 양방향으로 임의의 수의 변환 단계를 수행 할 수 있음을 의미합니다.

이것이 언급되지 않은 이상한 기능인 \uuuuuuxxxx 구문 의 이유입니다 .

번역 도구가 문자를 이스케이프하고 이미 이스케이프 된 시퀀스 인 시퀀스를 발견하면 추가 u 를 시퀀스에 삽입하여 \ucafe\uucafe 로 변환 해야 합니다. 의미는 변하지 않지만 다른 방향으로 변환 할 때 도구는 하나의 u 를 제거 하고 단일 u 를 포함하는 시퀀스 만 유니 코드 문자로 대체 해야 합니다. 이렇게하면 유니 코드 이스케이프도 앞뒤로 변환 할 때 원래 형식으로 유지됩니다. 아무도 그 기능을 사용한 적이 없다고 생각합니다…




Answer 3 Pepijn Schmitz


나는 나 자신을 도울 수 없기 때문에 완전히 비 효과적으로 포인트를 추가 할 것입니다. 아직 그것을 보지 못했습니다. 질문에 잘못된 전제가 포함되어 있기 때문에 질문이 유효하지 않다는 것입니다. 즉, 코드가 의견!

Java 소스 코드에서 \ u000d는 모든면에서 ASCII CR 문자와 동일합니다. 어디에서나 간단하고 끝이없는 줄입니다. 질문의 형식은 잘못된 것으로, 문자의 순서가 실제로 구문 상 일치하는 것은 다음과 같습니다.

public static void main(String... args) {
   // The comment below is no typo. 
   // 
 System.out.println("Hello World!");
}

IMHO의 가장 정확한 답은 다음과 같습니다. 코드가 주석에 없기 때문에 코드가 실행됩니다. 다음 줄에 있습니다. Java에서 "주석에서 코드 실행"은 예상 한대로 허용되지 않습니다.

혼동의 대부분은 구문 하이 라이터와 IDE가이 상황을 고려할만큼 정교하지 않다는 사실에서 비롯됩니다. 그들은 유니 코드 이스케이프를 전혀 처리하지 않거나 javac 와 같이 이전 대신 코드를 구문 분석 한 후에 수행합니다 .




Answer 4 zwol


\u000d 때문에 탈출 코멘트를 종료 \u 이스케이프가 균일하게 대응하는 유니 코드 문자로 변환 하기 전에 프로그램이 토큰 화됩니다. 당신은 동등하게 사용할 수 있습니다 \u0057\u0057 대신 //시작 코멘트를.

이것은 IDE의 버그이며 \u000d 가 주석을 끝내는 것을 분명히하기 위해 구문을 강조 표시해야합니다 .

언어의 디자인 오류이기도합니다. 이제는 수정할 수 없습니다. 그에 의존하는 프로그램이 손상 될 수 있습니다. \u 이스케이프는 "이해되는"문맥 (문자열 리터럴 및 식별자, 다른 곳은 아님)에서만 컴파일러가 해당 유니 코드 문자로 변환하거나 U + 0000에서 문자를 생성하는 것이 금지되어야합니다. 007F 범위 또는 둘 다 그 중 하나의 의미로 종료되는 주석을 방지했을 \u000d 사건을 방해하지 않고, 이탈 \u 이 그 이스케이프 유용하다 음표 포함 이용 \u 텍스트 편집기가 \u 이스케이프가 컴파일러보다 중요한 위치를 더 넓게 볼 수 있기 때문에 비 라틴어 스크립트에서 주석을 인코딩하는 방법으로 주석 내부를 이스케이프합니다. (I가 표시됩니다 어떤 에디터 나 IDE 인식하지 오전 \u 에서 해당 문자로 탈출 어떤 하지만, 문맥.)

C 계열에는 유사한 설계 오류가 있습니다. 1 주석 경계가 결정되기 전에 백 슬래시-줄 바꾸기가 처리됩니다. 예를 들어

// this is a comment \
   this is still in the comment!

나는이 특정 디자인 오류를 만들기가 쉽다는 것을 설명하기 위해 이것을 가져 왔으며, 토큰 화에 대해 생각하고 컴파일러 프로그래머가 생각하는 방식을 파싱하는 데 익숙하다면 오류를 수정하기에 너무 늦을 때까지 오류가 있다는 것을 깨닫지 못합니다. 토큰 화 및 파싱에 대해 기본적으로 공식 문법을 이미 정의한 경우 누군가 문법적인 특수 사례 (예 : 3 부작, 백 슬래시-줄 바꿈, ASCII로 제한되는 소스 파일에서 임의의 유니 코드 문자를 인코딩하는 등 무엇이든 포함해야 함)를 작성하는 것이 더 쉽습니다. 토크 나이저 앞에 변형 패스 추가 하여 토크 나이저를 재정 의하여 특수한 경우를 사용하는 것이 적절한 곳에주의를 기울이십시오.

1 pedants : 필자는 C의이 측면이 100 % 의도적이라는 것을 알고 있습니다. 이론적 근거는 아닙니다. 필자는 이것을 펀칭 된 카드에 임의로 긴 줄로 코드를 기계적으로 적용 할 수 있다는 것을 알고 있습니다. 여전히 잘못된 디자인 결정이었습니다.




Answer 5 Jonathan Gibbons


이것은 의도적 인 디자인 선택이었습니다. Java의 원래 디자인으로 거슬러 올라갑니다.

"코멘트에서 유니 코드 이스케이프를 원하는 사람?"을 묻는 사람들에게는 필자가 모국어가 라틴 문자 집합을 사용하는 사람들이라고 생각합니다. 다시 말해, 사람들은 Java 프로그램에서 합법적 인 곳이면 어디에서나 일반적으로 주석과 문자열로 임의의 유니 코드 문자를 사용할 수있는 Java의 원래 디자인에 내재되어 있습니다.

이러한 프로그램이 유니 코드 이스케이프를 해석 할 수없고 해당 글리프를 표시 할 수 없다는 소스 텍스트를 보는 데 사용되는 IDE (예 : IDE)와 같은 프로그램의 단점 일 수 있습니다.