2012-12-22 2 views
2

나는 bison/yacc (그리고 약간의 c를 리뷰)을 배우고 json 파서를 간단한 테스트 프로젝트로 만들려고한다.Pointers, bison and yacc

http://www.json.org/에있는 용어를 사용하여 문자열/값 쌍을 나타내는 구조체 쌍과 기본적으로 쌍의 연결된 목록에 대한 포인터가 들어있는 멤버 필드가있는 개체를 나타내는 struct 개체가 있습니다.

새로운 쌍을 반환하는 간단한 c 함수 (create_pair)가 있습니다. 내가 설명 할 수없는 이상한 행동을 알아 냈다.

  • "main"에서 이러한 함수를 호출하고 반환 된 구조체의 메모리 주소를 인쇄하면 해당 주소는 항상 다릅니다.
  • 내가 "들소"액션에서 아주 똑같은 함수를 호출하면, 내 함수가 항상 같은 메모리 주소에 상주하는 포인터를 반환한다는 것을 알 수 있습니다.

이것은 의미가 있습니까?

정보/코드 따르

  • http://pastebin.com/k272vVb5
  • : 여기

    코드 (링크, 네 개의 다른 파일을 가리키는 4 개 페이스트 빈 링크 목록이 "프로젝트"에 포함 된 포함)입니다

당신은 컴파일하고 그것을 실행할 수 있습니다

lex t.l 
yacc -d t.y 
cc y.tab.c lex.yy.c t.c 
./a.out 
,536,913 코드를 실행하고 다음과 같은 입력으로 실행하면 63,210

:

{ "firstName을": "A", "이 lastName": "B" }

해당가 표시됩니다

1) "주"(검사 파일 타이)에서 실행되는 코드는 그때 자신의 메모리 주소를 인쇄, 네 가지 쌍의 객체를 생성하고 출력 (통지 서로 다른 주소 같은)입니다 :

p 0x7fff52476be8 //(<-memory address for pair p) 
print pair: P, Hellov 
q 0x7fff52476bc8 //(<-memory address for pair q) 
print pair: Q, Hellox 

2) 위의 json 샘플을 붙여 넣자 마자 "pairName"에 대한 첫 번째로 "pair"규칙을 두 번 누르십시오. "A", 두 번째로 "lastName"규칙 : "B", 새 쌍을 만듭니다. 두 경우 모두 메모리 주소를 인쇄하면 동일합니다.

Creating pair 0x7fff52475c88 
print pair: firstName, A 
Creating pair 0x7fff52475c88 
print pair: lastName, B 

왜 이런 일이 발생합니까?

답변

2

pair의 주소가 무엇인지 신경 쓰지 않아야합니다. 그것들과 함께 수행되는 작업과는 무관하며,보고있는 주소는 부수적이며 결과가 없습니다.

함수 create_pair은 포인터를 반환하지 않습니다. pair create_pair(…)으로 선언되었으므로 값으로 pair을 반환합니다.

main에는 pair p = create_pair(l, v);을 정의합니다. 이렇게하면 자동 개체 p이 만들어지며 대개 스택에 해당 공간을 둡니다. 그런 다음 create_pair을 호출합니다. create_pair에 의해 반환 된 값은 p에 복사됩니다. 나중에 &p을 인쇄하면 create_pair이 반환 한 주소가 아닌 p의 주소가 인쇄됩니다.

마찬가지로, pair q = create_pair(l, x);을 정의하면 다른 개체 인 q이 생성됩니다. 이 개체의 수명이 p의 수명과 겹치기 때문에 다른 위치에 있어야하므로 주소가 다릅니다. &q을 인쇄하면이 다른 주소가 표시됩니다.

다음으로 Bison 규칙에 넣은 코드, pair p = create_pair($<u_string>1, $<u_value>3);을 고려해보십시오. Bison은 규칙을 처리 할 때이 코드를 실행합니다. 자동 개체를 만들고 주소를 인쇄합니다. 그런 다음 실행은이 코드의 범위를 벗어나고 Bison은 의심의 여지없이 다른 일을 계속 수행하며 현재 수행중인 처리를 종료합니다. 자동 개체의 수명이 끝나고 스택에 있던 데이터가 팝됩니다. 나중에, 들소는이 규칙에 돌아온다. 이 시점에서 컴퓨터는 기계적으로 작동하기 때문에 스택 포인터는 이전과 동일한 주소를 사용합니다. 따라서 새로운 p이 생성되면 이전의 p과 같은 위치에있게됩니다. 같은 시간에 존재했기 때문에 다른 장소에 있어야했던 pq과 달리이 이전 p과 새로운 p은 다른 시간에만 존재하므로 같은 위치에있을 수 있습니다.

항상 그런 것은 아닙니다. 문법이 좀 더 복잡하다면, Bison은 한 번에 다른 것들을 스택에 넣을 수도 있고, 그렇지 않을 수도 있습니다 (아마도 Bison가 파싱하는 파싱 머신은 그런 식으로 행동하지 않을 수 있습니다.) 또는 다른 규칙에 동일한 코드가있는 경우 해당 규칙이 처리 될 때 스택이 다를 수 있습니다.

+0

좋아,이 질문은 명확하고 정확한 대답 : 감사합니다! 그러나 이것에 대해 다시 생각해 봅시다 : "members"규칙이 히트 될 때 (멤버 : COMMA 쌍 구성원), $ 1과 $ 3의 값을 확인하는 것이 가능합니다 ($ 1은 멤버로부터 반환 된 값입니다 : 한 쌍). $ 1과 $ 3이 (가) 같은 쌍을 가리키고 있습니까? 희망이 분명하다. – user1417009

+0

@ user1417009 : 프로덕션'pair : string COLON value'에서'$$ = & p;'를 지정합니다. 우리가 배웠 듯이,'& p'는 스택에있는 자동 객체의 주소입니다. 이 규칙에 대한 코드가 블록을 종료하면 (이 할당 직후) 객체 수명이 끝나고 스택이 다른 용도로 다시 사용됩니다. 따라서이 '쌍'과 관련된 주소는 유효하지 않습니다. 실행이'members'에 대한 규칙에 도달하면,이 주소를 사용하려고 시도합니다.이 주소는'members'에 대한 객체를 가리키고 있습니다. [계속 ...] –

+0

자동 개체의 주소를'yylval' 개체에 보관해서는 안됩니다. 개체를 복사하거나 동적으로 할당 한 주소에 포인터를 사용해야합니다. –

0

그러면 스택 변수가 변경되는 주소가 표시됩니다. 어느 것이 정상입니다. 그들 모두가 같은 주소를 가지고 있다면, 당신은 하나의 값을 다른 주소로 덮어 쓰게 될 것이고, 이것은 그리 유용하지 않을 것입니다.

편집 : 함수를 호출 할 때 (예 : 호출자 함수에서).main) 스택 변수의 주소는 항상 동일합니다. 스택은 호출이 시작될 때 동일하게 시작되기 때문에 [일반적으로 컴파일러가 스택과 함께 재미있는 일을하기 때문에 100 % 보장되지 않습니다]

편집 2 : 명확하게 말하면 통화가 동일한 통화 체인 인 경우 함수 C의 함수 B에서 함수 A를 호출하면 호출은 B 또는 C의 어느 위치에서든 A에서와 동일합니다. 물론 함수 C에서 함수 D를 함수 A라고 부르는 경우 A의 로컬 변수 주소와 관련하여 모든 베팅이 해제됩니다. 물론 비슷하지만 함수 D에 큰 지역 변수가 있으면 매우 다르다]. 그리고 이것이 전형적이라는 경고는 여전히 적용됩니다. 컴파일러는 모든 단일 호출을 정리하지 않고 "신경 쓸 정도가 될 때까지"스택 정리를 떠날 수 있습니다. 따라서 함수 A를 세 번 호출하면 스택에 "쓰레기"가 축적되어 정리되지 않습니다 나중에까지.

나는 이것이 왜 이렇게 달라야한다고 생각하는지 조금 혼란 스럽습니까?

+0

글쎄, 1의 경우, 나는 항상 다른 메모리 주소 -> 놀랄 일이 아니다. 내가 바이슨 액션 (사례 2) 내에서 호출하자마자 반환 된 "쌍"은 항상 똑같은 주소 -> 사정을가집니다. 지금은 더 명확한가요?프로그램에서 실제로 발생하는 일은 그러한 변수가 실제로 덮어 쓰여진다는 것입니다 (예 : 구성원 규칙이 충족 될 때 어떤 일이 발생하는지 확인). – user1417009

+0

동일한 호출자로부터 함수가 호출 될 때 스택 포인터가 동일하다고 말하는 것은 맞지 않습니다. 'c'에서 호출되는'b'에서'a'가 호출 될 때,'d'에서 호출되는'b'에서'a'가 호출 될 때를 고려하십시오. 'c'와'd'에서 다른 스택을 사용하면'a'의 스택 포인터가 달라집니다. 또한 다른 변수가 선언 된 추가 범위가있는'b'의 한 점에서'a'를 호출하는 것과 같은 다른 것들이 스택에 영향을 줄 수 있습니다. –

+0

네, 스택 주소가 내 게시물의 [] 섹션에서 보장되지 않는다고 생각합니다. 하지만 일반적으로 함수 B에서 함수 A를 여러 번 호출하면 함수 B의 로컬 변수가 매번 동일하게됩니다. 어떤 수단으로 보장 할 수는 없지만 매우 일반적입니다. 나는 우리가 대략 같은 것을 설명했다고 생각한다 - 아니면 혼란 스럽다. –

관련 문제