2010-12-03 6 views
6

다음은 빠른 배경입니다. 유닉스 소켓을 통해 서로 통신하는 클라이언트와 서버 프로그램이 있습니다. 서버 쪽에서받은 메시지를 구문 분석 할 때 strncmp를 사용하여 수행 할 작업을 파악하려고합니다.strncmp 적절한 사용

내가 겪고있는 문제는 strncmp의 길이 인수에 정확히 무엇을 사용해야하는지 파악하는 것입니다. 이것이 문제가되는 이유는 내 메시지 중 일부가 공통 접두사를 공유하기 때문입니다. 예를 들어, 서버가 주 서버 주소로 응답하도록하는 "getPrimary"메시지와 서버가 주 서버의 상태로 응답하게하는 "getPrimaryStatus"메시지가 있습니다. 나는 서버 "getPrimaryStatus"strncmp 충분히 멀리 문자열에서 확인되지 않기 때문에, 코드가 항상 foo는 반환을 보낼 때

if(strncmp(message,"getPrimary",strlen("getPrimary"))==0){ 
    return foo; 
} 
else if(strncmp(message,"getPrimaryStatus",strlen("getPrimaryStatus"))==0){ 
    return bar; 
} 

이 가진 문제는 나의 초기 생각은 다음을 수행하는 것이 었습니다. strncmp의 길이 인수로 strlen (메시지)을 전달할 수 있지만 예상치 못한 입력이 발생할 경우 오버플로를 방지하기 위해 strncmp를 사용하는 목적을 무력화시키는 것 같습니다. 나는 읽을 수있는 최대 메시지 길이에 대한 정적 변수를 가지고 있지만, 메시지 오버플로가 발생하면 효과가 최소화되도록 길이를 지정하는 것과 같이 전달하는 것처럼 보입니다.

나는 몇 가지 해결책을 생각해 냈지만 그다지 예쁘지 않아이 문제를 다루는 일반적인 방법이 있는지 궁금해하고있었습니다. 참고로

, 내 현재의 솔루션은 다음과 같습니다 주문 내 경우/다른 경우 일반적인 접두사 어떤 메시지가 지뢰를 던질 수있는 정말 좋은 방법처럼 보인다 하강 길이의 순서 (체크되어있는 방식 문 나중에 뭔가를 추가하려는 누군가를위한 코드).

그룹 내 공통 접두어와 메시지를 함께 먼저 접미사을 찾습니다

if(strncmp(message,"getPrimary",strlen("getPrimary"))==0){ 
    if(strncmp(message,"getPrimaryStatus",strlen("getPrimaryStatus"))==0){ 
     return bar; 
    else 
     return foo; 
    } 
} 

을하지만 이것은 단지 내가 처리하고있어 약 20 개의 가능한 메시지가 특히 이후, 지저분한 느낌.

가능한 모든 메시지의 배열을 만들고 길이를 내림차순으로 정렬 할 함수를 내 init 시퀀스에 추가하고 일치하는 항목을 찾을 때까지 해당 코드의 요소를 검색합니다. 이것은 복잡하고 어리석은 것처럼 보입니다.

어딘가에 해결책이 있어야하는 공통된 문제 여야합니다.하지만 지금까지 아무 것도 찾을 수 없었습니다.

미리 도움을 청하십시오!

답변

4

message에서 문자열이 null로 종료 될을 가정이라고 가정하면, 유일한 이유는 경우에, 그것은 message의 끝을지나 찾고 방지하는하는 것보다는 strcmp()보다 여기 strncmp()를 사용하는 아니요은 null로 종료됩니다.이와 같이

, 당신은 strncmp()에 전달하는 nmessage의 수신 크기해야합니다 (메시지를 읽어 read()/ recv() 함수의 반환 값에서) 알아야 할있다.

/* len is a placeholder for whatever variable or function you use to get the length */ 
if ((len(a) == len(b)) && (strncmp(a, b, len(a)) == 0)) 
{ 
    /* Strings are equal */ 
} 

그렇지 않으면 당신이 당신의 비교보다 길거나 짧은 뭔가 일치 :

+0

가장 간단한 해결책 인 것 같습니다. 이것은 실제로 프로세스 간 통신을 용이하게하기 위해 유닉스 소켓을 사용하여 처음으로, 그리고 두 달 전 소켓 처리 코드를 썼다 ... 나는 읽은 바이트 수를 반환하는 read()를 사용하고 있다는 것을 완전히 잊었다! –

+0

대신 strncmp에 메시지 크기를 전달하는 것이 문제에 대한 불완전한 해결책이라고 생각합니다. 자세한 내용은 내 솔루션을 참조하십시오. –

+0

일치하는 문자가 많은 문자열 간의 비교는 "청킹"방식을 사용하면 가장 효율적으로 수행 할 수 있지만 초기에 다른 문자열 간의 비교는 한 번에 한 문자 씩 접근하여보다 효율적일 수 있습니다. "n"이 클 때 strncmp의 일부 구현이 청크를 사용하는 경우 놀라지 않을 것입니다. 그러나 일치 가능성이있는 유스 케이스와 가능성이 적은 유스 케이스에 별도의 기능이 있다면 좋을 것입니다. – supercat

0

1 년 전에 C 프로그래밍을 수행했던 내 기억을 파헤쳐 보면 세 번째 인수가 함수에 비교할 문자 수를 알려주고 있다고 생각합니다. strncmp()를 사용하지 마십시오

if(strncmp(message, "getPrimary", strlen("getPrimary")) { 
    // 
} 
0

: 당신이 그렇게해야 뭔가를

를 처리하는 방법에 많은 문자를 제어 할 수 있습니다로 안전 이유입니다. 대신 strlcmp()을 사용하십시오. 더 안전합니다.

+2

strlcmp()는 표준에 포함되지 않은 것 같습니다. 그리고 만약 내가 온라인에서 발견 된 구현이 전형적이라면, 한 문자열이 다른 문자열의 부분 집합이라면 그 행동은 strncmp()의 행동으로 변질된다. 그것은 OP가 원하지 않는 것입니다. –

1

버퍼 오버플로를 방지하기 위해 strncmp를 사용하고 있지만 메시지가 이미 메모리 (즉 메시지 버퍼)에 복사되어있는 것으로 느껴집니다.또한, 원형

int strncmp (const char * str1, const char * str2, size_t num); 

함수는 부작용이 없다는 것을 나타낸다 (즉, 그 입력 버퍼 중 하나를 변경하지 않는다) 그래서 버퍼를 덮어 메모리 변경 것이라는 위험이 없어야한다. (strcpy()의 경우는 아닙니다.)

메시지 버퍼의 길이가 가장 긴 명령 문자열보다 긴지 확인할 수 있습니다. 그렇게하면 자신이 소유 한 메모리에 항상 액세스하고 있다는 것을 확신 할 수 있습니다.

또한 strncmp 사용을 주장하는 경우 배열의 명령 목록을 저장하고 가장 큰 순서에서 가장 작은 순서로 정렬 할 수 있습니다. 각 문자열을 길이 (그리고 아마도 핸들러를 실행하는 함수 포인터)와 연관시킬 수 있습니다.

마지막으로 C++이지도를 호출하는 버전 또는 Ruby 또는 PHP 호출 연관 배열을 찾을 수 있습니다. 이렇게하면 라이브러리가이 if-else 트리를 효율적으로 올바르게 처리 할 수 ​​있습니다.

0

메시지에 다음 명령 중 하나 또는 명령 문자열 뒤에 공백/열기 괄호/etc가 포함되어 있습니까?

전자 메일 인 경우 strncmp을 입력하고 strcmp을 사용하십시오.

후자의 경우 isspace(message[strlen(command)]) 또는 message[strlen(command)]=='(' 또는 그 이상을 확인하기 만하면됩니다. (참고 : strlen(command)은 상수이므로 문자열 리터럴의 크기에서 가져 오기 위해 매크로를 사용하는 것이 좋습니다.)

+1

'sizeof ("KeyWord") - 1' -'sizeof()'도 터미널 널을 계산하기 때문입니다. 물론 컴파일 타임 상수입니다. –

+0

예, 모든 것을 언급해야한다고 생각합니다. –

2

한 가지 기술은 가장 긴 이름을 먼저 비교하는 것입니다. 또는 키워드가 들어있는 테이블)를 사용하십시오. 그러나 귀하의 예를 복용 :

GetPrimaryStatus 
GetPrimary 

당신은 아마 GetPrimaryIgnitionGetPrimary로 인식되지 않도록합니다. 따라서 두 문자열 중 더 긴 문자 또는 메시지의 길이를 비교해야합니다. 여기

귀하의 데이터 구조는 다음과 같을 수 있습니다 : 당신은 다음이 테이블을 통해 루프 관련 명령을 찾을 수 있습니다

static const struct 
{ 
    char *name; 
    size_t name_len; 
    int  retval; 
} Messages[] = 
{ 
    { "getPrimaryStatus", sizeof("getPrimaryStatus"), CMD_PRIMARYSTATUS }, 
    { "getPrimary",  sizeof("getPrimary"),  CMD_PRIMARY  }, 
    ... 
}; 

. 주의를 기울여야하는 범위를 제한 할 수 있습니다. sizeof() 값에는 문자열 끝에 NUL이 포함됩니다. 메시지를 null로 끝낼 수있는 경우 유용합니다.

그러나 메시지를 어딘가에 복사하거나 해당 위치에서 메시지를 수정하여 메시지에서 명령 단어를 null로 끝낼 수있는 경우가 훨씬 간단합니다. 그런 다음 strncmp() 대신 strcmp()을 사용하십시오. 가장 짧은 고유 접두사 조회는 코딩하기가 더 어렵습니다.

명령 단어를 찾는 가장 확실한 방법은 strcspn()입니다. 명령이 모두 영문자 또는 영숫자라고 가정합니다. message이 어디

0

두 문자열이 같은지 여부를 결정하기 위해 strncmp를 사용하는 유일한 안전한 방법은 문자열이 같은 길이가 있는지 사전에 확인하는 것입니다 :

strncmp(a, "test", strlen("test"))은 "테스트", "테스트 및 다른 문자의 전체 묶음"과 일치합니다.

strncmp(a, "test", strlen(a))은 "", "t", "te", "tes"와 일치합니다.

0

strcmp를 사용하고 두 문자열의 길이를 비교하십시오. 길이가 동일하면 strcmp가 찾는 결과를 제공합니다.