2017-01-18 2 views
3

나는 동시에 다른 회원들에게 노동 조합을 사용하는 것 같다 코드의 조각을 발견했습니다액세스 다른 회원 동시에

XEvent ev; 

if(handler[ev.type]) 
    (handler[ev.type])(&ev); 

핸들러 함수의 배열입니다. 다음은 XEvent의 정의입니다.

typedef union _XEvent{ 
    int type;/*must not be changed*/ 
    XAnyEvent xany; 
    XKeyEvent xkey; 
    XButtonEvent xbutton; 
............ 
} Xevent; 

XEvent의 모든 struct 멤버에는 첫 번째 멤버가 int로 있습니다. 호출 된 함수는 XEvent의 적절한 멤버 구조를 사용합니다.

void 
kpress(XEvent *ev) { 
    XKeyEvent *e = &ev->xkey; 

문제는 XKeyEvent 이벤트가 키를 누르거나 키 해제 여부를 결정하기 위해뿐만 아니라 첫 번째 INT 멤버의 값을 사용하는 것이다.

typedef struct { 
    int type; /* KeyPress or KeyRelease */ 
    unsigned long serial; /* # of last request processed by server */ 
    ............. 
} XKeyEvent; 

무엇이 여기에 있습니까?

참고 : 위의 코드는 간단한 터미널 인 터미널 에뮬레이터에 속합니다. 그리고 언급 된 모든 데이터 구조는 Xlib에 속합니다.

+0

'int'(원래 '유니온'에 있음) with-an-initial-int는 "안전하다"(아마 추측 할 수 있겠지만, 아마도 "작동한다"). 그러면 XKeyEvent의 _reading_에 문제가 보이지 않는다. (아마도'KeyPress' 와'KeyRelease'는'XEvent'가 처리하는 더 넓은 이벤트 유형 중 두 가지입니다. 아마도'struct {int type; 노조 {....}}'. – TripeHound

+0

@TripeHound : 다음에는 두 개의'type'이 있습니다. 하나는 외부 구조체이고 다른 하나는'union'의 다른 형식 앞에옵니다. 목표가 어떤 'X * Event'가 저장되었는지에 관계없이 'type'을 읽을 수있게하는 것 같습니다. – ShadowRanger

+0

@shadowranger가 정확히 요점입니다 - X11 시스템은 이벤트를 불투명 한 구조로 보냅니다. 누군가가 거기에 무엇이 있는지 알고 싶다면, 그는'type' 멤버를 체크하고 실제 데이터 멤버에 접근하기 위해 유니온을 캐스트 할 수 있습니다. 그것은 일종의 "OOP in C"입니다. – tofro

답변

2

그것은 동안을 잡았다 union에서 유효한 int 및 구조체를 입력합니다. 아니, 그렇지 않아.

Xlib는 KeyPress 및 KeyRelease 이벤트에 대해 동일한 XKeyEvent 구조를 사용합니다 (동일한 데이터 멤버를 사용하므로 두 경우 모두 사용할 수 있음).

X11 윈도우 시스템은 수신기 수 원래 구조 캐스트 (또는 OOP 용어 "유도 된 클래스"단위)에 따른 불투명 구조 (또는 OOP 용어 "기본 클래스"에서)로 XEvents 주위 보낸다 이벤트 유형. 겹쳐진 int 멤버 "유형"이 유형 선택자로 사용됩니다.

이것은 각 이벤트 유형을 처리 할 필요없이 일반 코드의 이벤트를 올바른 위치로 "라우트"할 수 있도록하기 위해 수행됩니다. 이해 관계자 (실제 수신자)만이 내부 유니온을 올바른 유형으로 캐스팅하고 관심있는 데이터 멤버를 "추출"합니다.

+0

아, 이제 알겠습니다. 'handler'는'ButtonPress'와'ButtonRelease'에 다른 엔트리를 가지고 있습니다. 어쩌면 앱이 키 누르기와 키어 넣기를 다르게 처리하지 못할 수도 있습니다. – saga

+0

. KeyPress와 KeyRelease. 그러나 버튼은 동일하게 작동합니다. – tofro

1

C99 (이전 표준 C)와 C11 이후에는 조합원이 마지막으로 작성한 멤버가 아니더라도 읽을 수 있습니다.

마지막으로 기록 된 멤버의 값이 읽는 멤버의 값으로 재 해석된다는 것을 설명합니다 (크기가 다른 경우 "예상 할 수있는 것처럼"동작합니다). 이 값은 트랩 값일 수 있지만 읽을 수있는 단순한 동작이 허용되며 정의되지 않은 동작은 허용되지 않습니다.

이제 표준에서는 동일한 초기 시퀀스를 공유하는 여러 멤버 구조가 공용 구조체에 포함되어있는 경우 공용 구조체를 통해 공용 시퀀스를 검사 할 수 있습니다. XEvent에서

type는 구조가 아니라 표준은 두 개의 추가 것을 말한다 : 첫 번째 멤버를 가리키는,

  1. 구조 포인터, 적절하게 변환합니다.
  2. 적절히 변환 된 유니온 포인터는 모든 유니온 멤버를 가리 킵니다.

는 각각의 구조체는 각각 typeXEvent에서 type 동일한 메모리 위치에 존재한다. 따라서 당신이 ev.type 또는 ev.xkey.type을 읽고 있든지간에 그것은 같은 int가 될 것입니다.

그래서 코드에서 무슨 일이 일어나고 있는지 :

  1. 노동 조합이 유형의 삭제에 사용됩니다. 올바른 처리기를 결정하는 데 type 필드 만 사용됩니다. 동일한 기능이 type의 여러 값으로 handler에 등록되지 않도록하는 것은 없습니다.

  2. 핸들러는 보려는 공용체 멤버를 알고 있으므로 xkey에 액세스합니다. 그런 다음 type 값에 따라 작동합니다.이벤트 사이의 1의 관계 : 실제로, 아무도 없기 때문에

    당신은 일이 있어야한다고 가정 할 것 ... - 나는 당신이 당신의 문제가 생각하는 곳 이해 될 때까지