문자열 상수와 문자열 리터럴의 차이점은 무엇입니까?
나는 Objective-C와 Cocoa를 배우고 있으며 다음과 같은 진술을 보았습니다.
Cocoa 프레임 워크는 문자열 리터럴이 아닌 전역 문자열 상수가 딕셔너리 키, 알림 및 예외 이름, 문자열을받는 일부 메소드 매개 변수에 사용되기를 기대합니다.
저는 높은 수준의 언어로만 작업 했으므로 문자열의 세부 사항을 그렇게 많이 고려할 필요가 없었습니다. 문자열 상수와 문자열 리터럴의 차이점은 무엇입니까?
Objective-C에서 구문 @"foo"
은 불변 의 리터럴 인스턴스입니다 NSString
. Mike가 가정하는 것처럼 문자열 리터럴에서 상수 문자열을 만들지 않습니다.
Objective-C 컴파일러는 일반적으로 컴파일 단위 내에서 인턴 리터럴 문자열을 수행 합니다. 즉, 동일한 리터럴 문자열의 여러 사용을 통합하며 링커가 단일 바이너리에 직접 연결된 컴파일 단위에서 추가 인턴을 수행 할 수 있습니다. (Cocoa는 변경 가능한 문자열과 변경 불가능한 문자열을 구분하고 리터럴 문자열도 항상 변경 불가능하므로 간단하고 안전 할 수 있습니다.)
반면에 상수 문자열은 일반적으로 다음과 같은 구문을 사용하여 선언되고 정의됩니다.
// MyExample.h - declaration, other code references this
extern NSString * const MyExampleNotification;
// MyExample.m - definition, compiled for other code to reference
NSString * const MyExampleNotification = @"MyExampleNotification";
여기에 구문 운동의 요점은 당신이 할 수 있다는 점이다 의 용도에 사용하는 문자열의 하나의 인스턴스 만이 있다는 보장함으로써 문자열 효율 도 여러 프레임 워크에서 같은 주소 공간 (공유 라이브러리). ( const
키워드 의 위치가 중요합니다. 포인터 자체가 일정하다는 것을 보장합니다.)
메모리를 굽는 것은 8MB RAM이있는 25MHz 68030 워크 스테이션의 시대만큼 큰 문제는 아니지만 문자열을 비교하는 데 시간이 걸릴 수 있습니다. 동일한 대부분의 시간 문자열이 포인터 같음을 확인하는 것도 도움이됩니다.
예를 들어 이름으로 개체의 알림을 구독하고 싶다고 가정 해 보겠습니다. 이름에 상수가 아닌 문자열을 사용 NSNotificationCenter
하면 알림을 게시하면 관심있는 사람을 결정할 때 많은 바이트 단위 문자열 비교가 수행 될 수 있습니다. 비교되는 문자열이 동일한 포인터를 가지고 있기 때문에 이러한 비교의 대부분이 단락되면 큰 승리가 될 수 있습니다.
일부 정의
리터럴 정의상 불변의 값이다. 예를 들면 : 10
의 상수는 읽기 전용 변수 또는 포인터이다. 예를 들면 : const int age = 10;
의 문자열 리터럴 과 같은 표현이다 @""
. 컴파일러는이를 NSString
. 문자열 상수 에 대한 읽기 전용 포인터이다 . 예 :NSString
NSString *const name = @"John";
마지막 줄에 대한 몇 가지 의견 :
- 그것은 상수 객체가 아니라 상수 포인터입니다 1 .
objc_sendMsg
2 는 객체를const
. 불변 객체를 원한다면 객체 내부에 불변성을 코딩해야합니다 3 . - 모든
@""
표현은 실제로 불변입니다. 그것들은 컴파일 타임에 4 개의 인스턴스 로 대체NSConstantString
되는데, 이것은NSString
고정 된 메모리 레이아웃 5 를 가진 특수 서브 클래스입니다 . 이것은 또한NSString
컴파일 타임 6 에서 초기화 될 수있는 유일한 객체 인 이유를 설명합니다 .
상수 문자열은 것 const NSString* name = @"John";
에 해당한다 NSString const* name= @"John";
. 여기서 구문과 프로그래머 의도가 모두 잘못되었습니다. const <object>
는 무시되고 NSString
인스턴스 ( NSConstantString
)는 이미 변경 불가능합니다.
1 키워드 const
는 바로 왼쪽에있는 모든 항목에 적용됩니다. 왼쪽에 아무것도 없으면 바로 오른쪽에있는 모든 항목에 적용됩니다.
2 이것은 런타임이 Objective-C의 모든 메시지를 보내는 데 사용하는 함수이므로 개체의 상태를 변경하는 데 사용할 수 있습니다.
3 예제 : in const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects];
const는 마지막 문장을 막지 않습니다.
4 식을 다시 작성하는 LLVM 코드 RewriteModernObjC::RewriteObjCStringLiteral
는 RewriteModernObjC.cpp에 있습니다.
5NSConstantString
정의 를 보려면 Xcode에서 cmd를 누른 채 클릭합니다.
6 다른 클래스에 대한 컴파일 시간 상수를 만드는 것은 쉽지만 컴파일러가 특수 하위 클래스를 사용해야합니다. 이로 인해 이전 Objective-C 버전과의 호환성이 깨집니다.
견적으로 돌아 가기
Cocoa 프레임 워크는 문자열 리터럴이 아닌 전역 문자열 상수가 딕셔너리 키, 알림 및 예외 이름, 문자열을받는 일부 메소드 매개 변수에 사용되기를 기대합니다. 선택할 수있는 경우 항상 문자열 리터럴보다 문자열 상수를 선호해야합니다. 문자열 상수를 사용하면 컴파일러의 도움을 받아 맞춤법을 검사하고 런타임 오류를 방지 할 수 있습니다.
리터럴은 오류가 발생하기 쉽다고 말합니다. 그러나 그들은 또한 더 느리다고 말하지 않습니다. 비교:
// string literal
[dic objectForKey:@"a"];
// string constant
NSString *const a = @"a";
[dic objectForKey:a];
In the second case I'm using keys with const pointers, so instead [a isEqualToString:b]
, I can do (a==b)
. The implementation of isEqualToString:
compares the hash and then runs the C function strcmp
, so it is slower than comparing the pointers directly. Which is why constant strings are better: they are faster to compare and less prone to errors.
If you also want your constant string to be global, do it like this:
// header
extern NSString *const name;
// implementation
NSString *const name = @"john";
Let's use C++, since my Objective C is totally non-existent.
If you stash a string into a constant variable:
const std::string mystring = "my string";
Now when you call methods, you use my_string, you're using a string constant:
someMethod(mystring);
Or, you can call those methods with the string literal directly:
someMethod("my string");
The reason, presumably, that they encourage you to use string constants is because Objective C doesn't do "interning"; that is, when you use the same string literal in several places, it's actually a different pointer pointing to a separate copy of the string.
For dictionary keys, this makes a huge difference, because if I can see the two pointers are pointing to the same thing, that's much cheaper than having to do a whole string comparison to make sure the strings have equal value.
Edit: Mike, in C# strings are immutable, and literal strings with identical values all end pointing at the same string value. I imagine that's true for other languages as well that have immutable strings. In Ruby, which has mutable strings, they offer a new data-type: symbols ("foo" vs. :foo, where the former is a mutable string, and the latter is an immutable identifier often used for Hash keys).
'Program Tip' 카테고리의 다른 글
dockerfile을 통해 docker 이미지를 빌드하는 동안 cmd 행을 통해 ENV 변수를 전달할 수 있습니까? (0) | 2020.12.08 |
---|---|
Go에서 2D 슬라이스를 만드는 간결한 방법은 무엇입니까? (0) | 2020.12.08 |
Git에서 브랜치를 별칭으로 지정할 수 있습니까? (0) | 2020.12.08 |
C # 코드에서 (큰) XML을 구문 분석하는 가장 좋은 방법은 무엇입니까? (0) | 2020.12.08 |
Postgresql의 where 절에서 별칭 열 사용 (0) | 2020.12.08 |