2012-03-13 4 views
0

매크로 정의를 매크로 파일과 본문의 두 문자열로 구문 분석합니다. 예를 들어 여기 내 메이크 파일에서 매크로 정의 라인은 다음과 같습니다C 프로그래밍 문자열 파싱

매크로-1 = 몸-1

내 코드는 버스 오류/세그먼트 오류를 ​​생성합니다.

static void parse_macro_def(const char* line) 
{ 
    char* m_name; 
    int name_pos = 0; 

    int i = 0; 
    while(line[i++] != '=')     //iterate until an equal sign is found 
    { 
     if(!isspace(line[i]))   //copy characters to m_name unless the character is whitespace 
     { 
     m_name[name_pos++] = line[i]; 
     } 
    } 
} 
m_name[name_pos] = '\0'; 

m_name 모든 도움을 매크로-1 감사로 설정해야합니다!

+2

줄에'= '기호가 없으면 세그먼트 화 오류가 발생할 수 있습니다. – dreamlax

+2

또한'm_name'을위한 공간을 할당하지 않습니다. 포인터 값은 불확정합니다. 즉, 가리 키기를 원하지 않는 곳을 가리 킵니다. – dreamlax

+0

'strtok()'을 사용하면 더 쉽게 사용할 수 있습니다. –

답변

1

m_name을 초기화하지 않으므로 임의의 위치를 ​​차지하므로 무작위로 작성하고 충돌합니다.

모든 경우에 덮어 쓰지 않도록 공간을 할당하고 반환하거나 (공백 길이와 함께) 공백을 전달해야합니다.


매크로 이름의 공백 문자는 매크로 정의의 버그입니다. 공백을 선도 할 수 있습니다. 후행 공백이있을 수 있습니다. 그러나 이름의 중간에 공백이 있어서는 안됩니다. 자, 당신이 유효하다고 생각한다면, 구문 분석을 위해 Makefile을 사용하면이 미묘함을 무시하고 도망 갈 수 있습니다. make 대체품을 쓰고 있다면 그럴 수 없습니다.

문자열에 등호가 있음을 이전에 확인한 경우가 아니라면 문자열 끝에서 벗어나지 않도록 확인해야합니다 (NUL '\0' 지나서 스캔하지 않음). 사실 강력한 코드를 사용하면 아마도 편집증에서 벗어날 수 있습니다.

while (line[i] != '\0' && line[i] != '=') 
{ 
    ... 
} 

그리고, 그것을 쓰는 동안, 나는 당신이 while 상태 i 증가하고 다음 문자가 루프의 몸에 공백이 있는지 여부를 확인 깨달았다. 그건 약간 관습 적입니다. 매크로 건너 경우 루프 조건이 O을 확인할 때

MACRO=value 

당신은 m_name=를 복사합니다. AFAICS에서는 M을 복사하지 않습니다.

m_name[name_pos] = '\0'; 

어떤 기능 때문에 구문 오류를 벗어나는 : 당신의 라인


참고.

+0

'm_name'이 범위를 벗어났다는 가정하에 오타가 발생했습니다. 컴파일을 고려하여 segfault를 얻었습니다. – dreamlax

+0

@dreamlax : 나는 그것이 실패한 정확한 코드를 보지 못하고 있다는 것을 의미한다고 생각하기 때문에, 그를 신뢰할 수있게 도와 줄 실제 방법이 없습니다. 우리는 뻔뻔스럽게 명백하게 지적 할 수 있지만 그게 전부입니다. –

+0

감사합니다 !! 구문 분석이 작동하는데 범위를 벗어난 m_name은 오타였습니다. 또한, 이전에 문자열에 등호가 있는지 확인했습니다. – CodeKingPlusPlus

0

m_name은 불확실합니다. 값을 할당하지 않았습니다. 아마 malloc 또는 calloc에 대한 호출의 반환 값을 할당하려고합니다.

또한 회선에 =이 포함되어 있지 않으면 루프가 끝까지 읽히게됩니다. 루프가 = 또는 끝에 도달하면 루프가 종료되는지 확인해야합니다 (필요에 따라 '\n' 또는 '\0' 일 수 있음).

0

코드에 몇 가지 결함이 있습니다 (예 : 줄의 첫 번째 문자를 확인/복사하지 않습니다 (즉, i가 즉시 증가하기 때문입니다).또한 m_name 포인트가 없습니다 (정의되지 않았습니다).

일반적으로 조금 다른 접근 방식을 사용합니다. 공백을 예상하고 싶지는 않지만 현재 (코드가 작동한다고 가정하면) 모든 것을 연결합니다. "some value = something"(이것이 유효한 코드가 아님을 안다)는 모든 공백 문자를 건너 뛰기 때문에 "somevalue"라는 변수 이름이됩니다.

나는 이런 식으로 뭔가를 (이 늦게 나는 졸린, 그래서 몇 가지 버그를 포함 할 수 있습니다,하지만 당신이 수행하려고 할 수 있는지에 대한 몇 가지 아이디어를 제공해야합니다) 사용하십시오 : 또한

char name[256]; 
const char *start = line; // points to beginning of the line 
const char *end = strchr(line, '='); // returns a pointer to the position where there's an equal sign (if there's any; 0 otherwise) 
if (end) { // only try to parse if there's an equal sign 
    for(; start < end && isspace(*start); ++start); // this will effectively remove all leading space characters 
    for(; end > start && isspace(*(end - 1)); --end); // this will effectively remove all trailing space characters 
    strncpy(name, start, end - start); // copy the name 
    // do something else here 
} 

을 , 다른 부분에서 무엇을 할 것인지에 따라 일종의 정규 표현식 라이브러리 (추가 된 오버 헤드가 가치가 있고 프로젝트에 따라 다름)를 사용하고 \s*(.*?)\s*=과 같은 표현식을 사용하는 것이 유용 할 수 있습니다.