argv의 인코딩은 무엇입니까?
C의 경우 어떤 인코딩이 사용되는지 확실하지 않습니다.argv특히 다음 시나리오에 관심이 있습니다.
- 사용자가 L1 로케일을 사용하여 이름이 다음과 같은 파일을 만듭니다.
NASCII가 아닌 문자 포함 - 나중에 사용자는 L2 로케일을 사용하여 명령줄에서 해당 파일의 이름을 탭 완료하고 명령줄 인수로 프로그램 P에 입력합니다.
P는 명령줄에서 어떤 바이트 시퀀스를 볼 수 있습니까?
(했습니다. UTF-8 파일 이름은 다음과 같습니다.zw_TW.big5로케일은 내 프로그램 P가 UTF-8이 아닌 공급되도록 하는 것 같습니다.Big5가 ""OS X" "" "" "" P" "" ""를 받게 .Big5인코딩된 파일 이름.
지금까지 제가 생각한 것은 다음과 같습니다(오래전부터, 그리고 제가 아마 틀렸고 고쳐져야 할 필요가 있습니다).
창문들
파일 이름은 일부 유니코드 형식으로 디스크에 저장됩니다.는 Windows라는 합니다.N 페이지의 L1(으)로 합니다.N우리가 부를게요N1 및스어를 저장합니다.N1디스크에
나중에 탭을 완료할 때 이름이N1로케일 L2(새 현재 코드 페이지)로 변환되어 표시됩니다.운이 좋다면, 이것은 원래의 이름을 만들어 낼 것입니다.N하지만 이것은 사실이 아닐 것입니다.NL2에 표시할 수 없는 문자가 포함되어 있습니다.우리는 새로운 이름을 부릅니다.N2.
키를 키를 누릅니다.N2유니코드로 다시 변환되어 생성됩니다.N1이 또. 이. 거.N1 UCS2를 할 수 있습니다.GetCommandLineW/wmain/tmain하지만 사용자는GetCommandLine/main " 이이표시다니됩"가 됩니다.N2현재 로케일(코드 페이지).
OS X
디스크 스토리지 이야기는 제가 알기로는 동일합니다.OS X는 파일 이름을 유니코드로 저장합니다.
유니코드 단말기의 경우 단말기가 유니코드 버퍼에 명령 줄을 참조하십시오.탭이 완료되면 파일 이름을 유니코드 파일 이름으로 해당 버퍼에 복사합니다.
로케일인 되고 L2를 통해 됩니다.argv그리고 프로그램은 현재 로케일이 있는 argv를 유니코드로 디코딩하여 표시할 수 있습니다.
리눅스
리눅스에서는 모든 것이 다르고 저는 무슨 일이 일어나고 있는지 매우 혼란스럽습니다.Linux는 파일 이름을 유니코드가 아닌 바이트 문자열로 저장합니다.그래서 이름을 가진 파일을 만든다면,N에서 L1로 표시됩니다.N바이트 문자열이 디스크에 저장됩니다.
나중에 터미널을 실행하고 이름을 탭 완료하려고 하면 어떻게 되는지 잘 모르겠습니다.명령줄이 바이트 버퍼로 구성되어 있고 바이트 문자열인 파일의 이름이 해당 버퍼에 연결되어 있는 것처럼 보입니다.표준 문자를 입력하면 해당 버퍼에 추가되는 바이트로 즉시 인코딩됩니다.
당신이 프로그램을 실행할 때, 나는 그 버퍼가 직접 전송된다고 생각합니다.argv을 하나요?argvhave? L2 로케일에 있는 동안 명령줄에 입력한 문자는 L2 인코딩에 포함되지만 파일 이름은 L1 인코딩에 포함됩니다.그렇게argv두 인코딩이 혼합되어 있습니다!
질문.
여기서 무슨 일이 일어나고 있는지 누군가가 저에게 알려주시면 정말 좋겠습니다.지금 제가 가지고 있는 것은 추측과 추측의 반뿐이고, 그것은 정말로 서로 맞지 않습니다.제가 정말로 진실로 하고 싶은 것은argv현재 코드 페이지(Windows) 또는 현재 로케일(Linux/OS X)에 인코딩되어야 하지만 그렇지 않은 것 같습니다.
엑스트라
다음은 인코딩을 직접 관찰할 수 있는 간단한 후보 프로그램 P입니다.
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Not enough arguments\n");
return 1;
}
int len = 0;
for (char *c = argv[1]; *c; c++, len++) {
printf("%d ", (int)(*c));
}
printf("\nLength: %d\n", len);
return 0;
}
사용할 수 있습니다.locale -a로케일 및 export LC_ALL=my_encoding로케일을 변경할 수 있습니다.
모두의 답변에 감사드립니다.저는 이 문제에 대해 많은 것을 배웠고 제 질문을 해결한 다음과 같은 것들을 발견했습니다.
설명한 바와 같이 Windows에서는 현재 코드 페이지를 사용하여 argv를 인코딩합니다.그러나 GetCommandLineW를 사용하여 명령줄을 UTF-16으로 검색할 수 있습니다.코드 페이지가 더 이상 사용되지 않으므로 유니코드가 지원되는 최신 Windows 앱에는 argv를 사용하지 않는 것이 좋습니다.
유닉스에서는 argv에 고정 인코딩이 없습니다.
tab-completion/globing에 의해 삽입된 파일 이름은 디스크에서 이름이 지정되는 바이트 시퀀스와 정확히 동일한 argv 동사형으로 발생합니다.이는 해당 바이트 시퀀스가 현재 로케일에서 의미가 없는 경우에도 마찬가지입니다.
IME를 사용하여 사용자가 직접 입력한 입력은 로케일 인코딩에서 argv로 발생합니다. (Ubuntu는 로케일을 사용하여 IME 입력을 인코딩하는 방법을 결정하는 것으로 보이며, OS X는 Terminal.app 인코딩 기본 설정을 사용합니다.)
이것은 명령행 인수를 문자열로 처리하려는 Python, Haskell 또는 Java와 같은 언어에 짜증나는 일입니다.그들은 어떻게 해독할지 결정해야 합니다.argv내부적으로 사용되는 인코딩은 무엇이든.String(해당 언어의 경우 UTF-16).그러나 로케일 인코딩을 사용하여 이 디코딩을 수행하는 경우 입력의 유효한 파일 이름이 디코딩되지 않아 예외가 발생할 수 있습니다.
Python 3에서 채택한 이 문제에 대한 해결책은 대리 바이트 인코딩 체계(http://www.python.org/dev/peps/pep-0383/) 로, argv에서 코드화할 수 없는 바이트를 특수 유니코드 코드 포인트로 나타냅니다.해당 코드 포인트가 바이트 스트림으로 다시 디코딩되면 원래 바이트가 다시 됩니다.이렇게 하면 현재 인코딩에서 유효하지 않은 argv(즉, 현재 로케일이 아닌 다른 곳에서 이름이 지정된 파일 이름)의 데이터를 네이티브 Python 문자열 유형을 통해 정보 손실 없이 바이트로 라운드 트립할 수 있습니다.
보시다시피, 상황이 꽤 지저분합니다 :-)
지금은 Windows에 대해서만 말할 수 있습니다.Windows에서 코드 페이지는 레거시 응용 프로그램만을 위한 것이며 시스템이나 최신 응용 프로그램에서 사용되지 않습니다.Windows는 텍스트 표시, 파일 이름, 터미널, 시스템 API 등 모든 작업에 UTF-16을 사용합니다. 간의 한 한 는 두 번 됩니다. UTF-16은 UTF-16과 동일한 함수입니다.).FunctionW 작업을 UTF-16 문자열을 하며 하나의 함수인 UTF-16은 UTF-16과 같은 기능을 사용합니다.FunctionA) 에서 UTF-16으로으로, UTF-16을 UTF-16이라고 .FunctionW결과를 다시 변환합니다.콘솔에서도 UTF-16만 사용하기 때문에 탭 완료는 항상 UTF-16 문자열을 생성해야 합니다(TrueType 글꼴을 사용할 때 확실히 생성됩니다).탭으로 작성된 UTF-16 파일 이름이 애플리케이션에 전달됩니다. 응용 프로그램 이해애인즉이션이레케경거애션이우케시, 플리용사)을 사용하는 경우main에 wmain/GetCommandLineW( Microsoft C 런타임은 ( 등), 그런다 Microsoft C를 사용합니다.GetCommandLineA시스템이 명령줄을 변환하도록 합니다.을 완료하는 동안 되지 않을 ). 즉, Windows에 대해 말씀하신 것입니다.argv원래 프로그램이 사용한 코드 페이지(L1)의 정보가 중간 UTF-16 단계 동안 되돌릴 수 없이 손실되었기 때문에 배열은 항상 현재 응용 프로그램의 코드 페이지에 인수를 포함합니다.
결론은 항상 Windows에서 내려집니다.기존 코드 페이지를 사용하지 마십시오. 가능한 경우 UTF-16 API를 사용하십시오.이 사해야하경우를 사용해야 .main에 wmain하려면), (예: 플랫독립예사), 사용GetCommandLineW argvvmdk
테스트 앱의 출력을 이해하기 위해 수정해야 합니다. 16진수 코드가 필요하고 음수 값을 제거해야 합니다.또는 UTF-8 특수 문자와 같은 것을 인쇄하여 읽을 수 없습니다.
먼저 수정된 SW:
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Not enough arguments\n");
return 1;
}
int len = 0;
for (unsigned char *c = argv[1]; *c; c++, len++) {
printf("%x ", (*c));
}
printf("\nLength: %d\n", len);
return 0;
}
UTF-8을 사용하는 Ubuntu 박스에서 이 출력을 확인할 수 있습니다.
$> gcc -std=c99 argc.c -o argc
$> ./argc 1ü
31 c3 bc
Length: 3
제 경우 ü는 2자 이상으로 인코딩되고, 1은 단일 문자임을 알 수 있습니다.UTF-8 인코딩에서 기대하는 것과 정확히 일치합니다.
이것은 실제로 envLAN 변수에 있는 것과 일치합니다.
$> env | grep LANG
LANG=en_US.utf8
이것이 리눅스 사례를 조금 더 명확하게 하기를 바랍니다.
/행운을 빕니다
예, 사용자는 일반적으로 유닉스에서 로케일을 혼합할 때 주의해야 합니다.파일 이름을 표시하고 변경하는 GUI 파일 관리자에도 이 문제가 있습니다.Mac OS X에서 표준 Unix 인코딩은 UTF-8입니다.실제로 HFS+ 파일 시스템은 유닉스 인터페이스를 통해 호출될 때 UTF-8 파일 이름을 적용합니다. 파일 시스템 자체에 저장하기 위해 UTF-16으로 변환해야 하기 때문입니다.
언급URL : https://stackoverflow.com/questions/5408730/what-is-the-encoding-of-argv
'codememo' 카테고리의 다른 글
| 각진 강한 유형의 반응형 (0) | 2023.07.17 |
|---|---|
| Oracle SQL에서 상위 행의 모든 재귀 자식을 검색하는 방법은 무엇입니까? (0) | 2023.07.17 |
| char *를 LPWSTR로 변환 (0) | 2023.07.17 |
| 유형 스크립트와 함께 뷰에서 Mixins를 사용할 수 없습니다. (0) | 2023.07.13 |
| 기본값이 아닌 인수는 기본값 인수를 따를 수 없는 이유는 무엇입니까? (0) | 2023.07.13 |