문제

컴파일러에 더 효율적인 방법과 문자열이 비어 있는지 확인하는 모범 사례는 무엇입니까?

  1. 문자열 길이 == 0인지 확인
  2. 문자열이 비어 있는지 확인(strVar == "")

또한 대답은 언어에 따라 달라지나요?

도움이 되었습니까?

해결책

예, 문자열 저장은 언어마다 다르기 때문에 언어에 따라 다릅니다.

  • 파스칼 유형 문자열: Length = 0.
  • C 스타일 문자열: [0] == 0.
  • .그물: .IsNullOrEmpty.

등.

다른 팁

C 스타일(널 종료) 문자열을 사용하는 언어에서는 다음과 비교합니다. "" 더 빨라질 것입니다.이는 O(1) 연산이지만 C 스타일 문자열의 길이는 O(n)입니다.

문자열 객체(C#, Java 등)의 일부로 길이를 저장하는 언어에서는 길이 확인도 O(1)입니다.이 경우 새로운 빈 문자열을 구성하는 오버헤드를 피하기 때문에 길이를 직접 확인하는 것이 더 빠릅니다.

.Net에서:

string.IsNullOrEmpty( nystr );

문자열은 null일 수 있으므로 .Length는 때때로 NullReferenceException을 발생시킵니다.

C 스타일(널 종료) 문자열을 사용하는 언어에서는 ""와 비교하는 것이 더 빠릅니다.

실제로 문자열의 첫 번째 문자가 '\0'인지 확인하는 것이 더 나을 수 있습니다.

char *mystring;
/* do something with the string */
if ((mystring != NULL) && (mystring[0] == '\0')) {
    /* the string is empty */
}

Perl에는 문자열이 정의되지 않은 세 번째 옵션이 있습니다.정의되지 않은 문자열에 액세스해도 분할 오류가 발생하지 않는다는 점만 빼면 이는 C의 NULL 포인터와 약간 다릅니다.

Java 1.6에서는 String 클래스에 새로운 메소드가 있습니다. 비었다

자카르타 공용 도서관도 있습니다. isBlank 방법.공백은 공백만 포함하는 문자열로 정의됩니다.

귀하의 질문이 .NET이라고 가정합니다.

문자열이 null인지 확인하려면 IsNullOrEmpty를 사용하세요. 예를 들어 TextBox.Text 등을 확인할 때 문자열이 null이 아니라는 것을 이미 알고 있다면 IsNullOrEmpty를 사용하지 말고 질문을 입력하세요.
그래서 제 생각에는 String.Length가 문자열 비교보다 성능이 떨어집니다.

이벤트 테스트를 했습니다(C#으로도 테스트했는데 결과는 동일했습니다).

Module Module1
  Sub Main()
    Dim myString = ""


    Dim a, b, c, d As Long

    Console.WriteLine("Way 1...")

    a = Now.Ticks
    For index = 0 To 10000000
      Dim isEmpty = myString = ""
    Next
    b = Now.Ticks

    Console.WriteLine("Way 2...")

    c = Now.Ticks
    For index = 0 To 10000000
      Dim isEmpty = myString.Length = 0
    Next
    d = Now.Ticks

    Dim way1 = b - a, way2 = d - c

    Console.WriteLine("way 1 took {0} ticks", way1)
    Console.WriteLine("way 2 took {0} ticks", way2)
    Console.WriteLine("way 1 took {0} ticks more than way 2", way1 - way2)
    Console.Read()
  End Sub
End Module

결과:

Way 1...
Way 2...
way 1 took 624001 ticks
way 2 took 468001 ticks
way 1 took 156000 ticks more than way 2

이는 비교가 문자열 길이 확인보다 더 많은 시간을 필요로 한다는 것을 의미합니다.

String.IsNullOrEmpty() .net 2.0 이상에서만 작동하며 .net 1/1.1의 경우 다음을 사용하는 경향이 있습니다.

if (inputString == null || inputString == String.Empty)
{
    // String is null or empty, do something clever here. Or just expload.
}

""는 객체를 생성하기 때문에 "" 대신 String.Empty를 사용합니다. 반면 String.Empty는 그렇지 않습니다. 작고 사소한 것을 알고 있지만 필요하지 않을 때는 객체를 생성하지 않는 편이 낫습니다!(원천)

실제로 IMO에서 결정하는 가장 좋은 방법은 문자열 클래스의 IsNullOrEmpty() 메서드입니다.

http://msdn.microsoft.com/en-us/library/system.string.isnullorempty.

업데이트:나는 .Net이 다른 언어에서는 다를 수 있다고 가정했습니다.

이 경우 새로운 빈 문자열을 구성하는 오버헤드를 피하기 때문에 길이를 직접 확인하는 것이 더 빠릅니다.

@데릭파크:항상 그런 것은 아닙니다.""는 문자열 리터럴이므로 Java에서는 이미 인턴되어 있을 것이 거의 확실합니다.

C 문자열의 경우,

if (s[0] == 0)

둘 중 어느 쪽보다 빠를 거예요

if (strlen(s) == 0)

또는

if (strcmp(s, "") == 0)

함수 호출의 오버헤드를 피할 수 있기 때문입니다.

@나단

실제로 문자열의 첫 번째 문자가 '\0'인지 확인하는 것이 더 나을 수 있습니다.

그 얘기를 할 뻔했는데, 전화를 해서 결국 빼버렸어요. strcmp() 빈 문자열을 사용하고 문자열의 첫 번째 문자를 직접 확인하는 것은 모두 O(1)입니다.기본적으로 추가 함수 호출에 대한 비용을 지불하면 됩니다. 이는 매우 저렴합니다.만약 너라면 정말 하지만 최고의 속도가 필요하지만 첫 번째 문자와 0을 직접 비교해야 합니다.

솔직히 저는 항상 사용하고 있어요 strlen() == 0, 내가 가지고 있기 때문에 절대 이것이 실제로 측정 가능한 성능 문제인 프로그램을 작성했으며 이것이 확인을 표현하는 가장 읽기 쉬운 방법이라고 생각합니다.

다시 말하지만, 언어를 모르면 말할 수 없습니다.

그러나 나는 당신의 작업을 따르고 유지해야 하는 유지 관리 프로그래머에게 가장 적합한 기술을 선택하는 것이 좋습니다.

다음과 같이 원하는 것을 명시적으로 수행하는 함수를 작성하는 것이 좋습니다.

#define IS_EMPTY(s) ((s)[0]==0)

또는 비교할 수 있습니다.이제 당신이 확인하고 있다는 것은 의심의 여지가 없습니다.

이 스레드를 읽은 후 저는 약간의 실험을 수행했는데, 그 결과 두 가지 뚜렷하고 흥미로운 결과가 나왔습니다.

다음을 고려하세요.

strInstallString    "1" string

위 내용은 Visual Studio 디버거의 로컬 창에서 복사되었습니다.다음 세 가지 예 모두에서 동일한 값이 사용되었습니다.

if ( strInstallString == "" ) === if ( strInstallString == string.Empty )

다음은 기본적으로 동일한 두 가지 사례에 대해 Visual Studio 2013 디버거의 디스어셈블리 창에 표시되는 코드입니다.

if ( strInstallString == "" )
003126FB  mov         edx,dword ptr ds:[31B2184h]
00312701  mov         ecx,dword ptr [ebp-50h]
00312704  call        59DEC0B0            ; On return, EAX = 0x00000000.
00312709  mov         dword ptr [ebp-9Ch],eax
0031270F  cmp         dword ptr [ebp-9Ch],0
00312716  sete        al
00312719  movzx       eax,al
0031271C  mov         dword ptr [ebp-64h],eax
0031271F  cmp         dword ptr [ebp-64h],0
00312723  jne         00312750

if ( strInstallString == string.Empty )
00452443  mov         edx,dword ptr ds:[3282184h]
00452449  mov         ecx,dword ptr [ebp-50h]
0045244C  call        59DEC0B0        ; On return, EAX = 0x00000000.
00452451  mov         dword ptr [ebp-9Ch],eax
00452457  cmp         dword ptr [ebp-9Ch],0
0045245E  sete        al
00452461  movzx       eax,al
00452464  mov         dword ptr [ebp-64h],eax
00452467  cmp         dword ptr [ebp-64h],0
0045246B  jne         00452498

if( strInstallString == string.Empty )가 크게 다르지 않습니다.

if ( strInstallString.Length == 0 )
003E284B  mov         ecx,dword ptr [ebp-50h]
003E284E  cmp         dword ptr [ecx],ecx
003E2850  call        5ACBC87E        ; On return, EAX = 0x00000001.
003E2855  mov         dword ptr [ebp-9Ch],eax
003E285B  cmp         dword ptr [ebp-9Ch],0
003E2862  setne       al
003E2865  movzx       eax,al
003E2868  mov         dword ptr [ebp-64h],eax
003E286B  cmp         dword ptr [ebp-64h],0
003E286F  jne         003E289C

.NET Framework 버전 4.5의 NGEN 모듈에서 생성된 위의 기계어 코드 목록에서 다음과 같은 결론을 도출했습니다.

  1. 빈 문자열 리터럴과 System.string 클래스의 정적 string.Empty 속성에 대한 동일성을 테스트하는 것은 모든 실제적인 목적에서 동일합니다.두 코드 조각 사이의 유일한 차이점은 첫 번째 이동 명령의 소스이며 둘 다 ds를 기준으로 한 오프셋입니다. 이는 둘 다 기본 제공 상수를 참조함을 의미합니다.

  2. 리터럴 또는 string.Empty 속성으로 빈 문자열에 대한 동일성을 테스트하면 다음을 나타내는 두 개의 인수 함수 호출이 설정됩니다. 불평등 0을 반환하여.나는 몇 달 전에 수행한 다른 테스트를 바탕으로 이 결론을 내렸습니다. 이 테스트에서는 관리/비관리 구분에 걸쳐 내 코드 중 일부를 따랐습니다.모든 경우에 둘 이상의 인수가 필요한 모든 호출은 첫 번째 인수를 ECX 레지스터에 넣고 두 번째 인수를 레지스터 EDX에 넣습니다.후속 인수가 어떻게 전달되었는지 기억이 나지 않습니다.그럼에도 불구하고 호출 설정은 __stdcall보다는 __fastcall에 더 가깝습니다.마찬가지로 예상되는 반환 값은 거의 보편적인 EAX 레지스터에 항상 표시됩니다.

  3. 문자열 길이를 테스트하면 테스트 중인 문자열의 길이인 1(EAX 레지스터에서)을 반환하는 단일 인수 함수 호출이 설정됩니다.

  4. 즉시 눈에 보이는 기계어 코드가 거의 동일하다는 점을 감안할 때, 보고된 문자열 길이에 대한 문자열 동등성 성능이 더 나은 것을 설명할 수 있는 유일한 이유는 다음과 같습니다. 시니 비교를 수행하는 두 개의 인수 함수가 문자열 인스턴스에서 길이를 읽는 단일 인수 함수보다 훨씬 더 잘 최적화된다는 것입니다.

결론

원칙적으로 빈 문자열 리터럴은 소스 코드에서 모호하게 나타날 수 있으므로 빈 문자열을 리터럴로 비교하는 것을 피합니다.이를 위해 내 .NET 도우미 클래스에서는 오랫동안 빈 ​​문자열을 상수로 정의해 왔습니다.내가 사용하지만 문자열.비어 있음 직접 인라인 비교의 경우 상수는 값이 빈 문자열인 다른 상수를 정의하기 위해 유지됩니다. 상수를 할당할 수 없기 때문입니다. 문자열.비어 있음 그 가치로.

이 연습은 둘 중 하나와 비교하는 데 드는 비용에 대해 내가 가질 수 있는 모든 우려를 완전히 해결합니다. 문자열.비어 있음 또는 도우미 클래스에서 정의한 상수입니다.

그러나 이를 대체하기에는 난해한 질문도 제기됩니다.왜 비교하는거야? 문자열.비어 있음 문자열 길이를 테스트하는 것보다 더 효율적입니까?아니면 루프가 구현되는 방식으로 인해 Shinny가 사용하는 테스트가 무효화됩니까?(믿기 힘들지만, 나도 이전에 속았던 적이 있습니다. 여러분도 그럴 거라고 확신합니다!)

나는 오랫동안 그렇게 생각해왔다. 시스템.문자열 개체는 COM에서 오랫동안 알려져 온 BSTR(기본 문자열)과 근본적으로 유사한 계산된 문자열이었습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top