2011-01-21 4 views
1

IRC의 누군가와 토론을했고이 질문이 나타났습니다. 표준에 따라 유형 int의 객체를 char lvalue로 변경할 수 있습니다.앨리어싱 규칙이 대칭입니까?

int a; 
char *b = (char*) &a; 
*b = 0; 

정렬을 잘하면 반대 방향으로이 작업을 수행 할 수 있습니까?

제가 보는 문제는 앨리어싱 규칙이 하나가

int a; 
a = 0; 

이유는 비 대칭 관계로 앨리어싱 규칙을 고려하면, 다음의 간단한 경우를 포함 각 것을하지 않는다는 것입니다 객체는 sizeof(obj)unsigned char 객체의 시퀀스 ("객체 표현"이라고 함)를 포함합니다. int을 변경하면 해당 개체의 일부 또는 전부가 변경됩니다. 그러나 앨리어싱 규칙에는 intchar 또는 unsigned char으로 변경할 수 있지만 다른 방법은 사용할 수 없다고 명시되어 있습니다. 또 다른 예는

int a[1]; 
int *ra = a; 
*ra = 0; 

하나 개의 방향은 3.10/15 ("포함 ... 집계 또는 조합 유형")에 의해 설명하지만 이번에는 우리는 요소가 주변의 다른 방법 ("A 형식이 필요합니다 또는 집계의 비 정적 데이터 멤버 유형 ... ").

다른 방향이 암시되어 있습니까? 이 질문은 C에도 적용됩니다.

+0

"반대 방향"이란 의미를 나타내는 코드를 추가해주십시오. 어떤 코드가 허용되지 않을 것이라고 생각하십니까? –

+0

@Rob 내가 보여 준 줄 알았는데. 어쩌면 나는 실패했다. 'a = 0'뿐만 아니라'a = 0'도 허용되지 않을 수도 있습니다. "A foo bar"의 "반대 방향"은 "foo에 포함 된 막대"를 의미합니다. 특히 불분명 한 점은 무엇입니까? –

+0

뜻한다면'char a = 'A'; int * pi = (int *) a; * pi = 'B';'그렇다면 그런 것은 처음부터 안전하다고 생각하지 않습니다. – Nawaz

답변

2

앨리어싱 규칙은 단순히 메모리에있는 특정 객체에 대해 하나의 "효과적인 유형"(C99 6.5.7 및 각주 73)이 있음을 나타내며 이러한 객체에 대한 액세스는 하나만 통과합니다 의 :

  • 포함하는 효과적인 유형 (예선은 constrestrict,뿐만 아니라 서명/서명되지 않은 다움이 다를 수 있음)
  • 구조체 또는 조합 하나 개의 유형
  • 문자 유형과 호환 유형

유효 유형은 고급으로 지정되지 않습니다. 물론 이것은 별칭 지정을 지정하는 데 사용되는 구조입니다. 그러나 그 의도는 단지 두 개의 다른 문자가 아닌 유형을 사용하여 동일한 객체에 액세스하지 않는다는 것입니다.

답변은 그렇습니다. 실제로 다른 방향으로 갈 수 있습니다.

+0

C99 표준 *이이 주장을 뒷받침 할 참조없이 무언가를 말하고자 함을 주장하고 나서 C에서 합법적 인 결론을 이끌어내는 것은 다소 과감한 움직임입니다. C99 표준은 매우 명확하며 거기에는 아무 것도 없습니다 귀하의 주장에 대한 증거. – user2719058

1

표준 (C99 6.3.2.3 §7)은 "그냥 괜찮습니다"와 같은 포인터 캐스트를 정의하며, 캐스팅 된 포인터는 같은 주소를 가리 킵니다. (CPU가 캐스트를 불가능하게하는 정렬을하지 않는 한 정의되지 않은 동작입니다.)

즉, 실제 캐스팅 자체는 문제가 없습니다. 데이터 조작을 시작하면 어떻게됩니까 ... 이제 구현 정의 된 또 다른 이야기입니다.

여기서 표준과 같습니다.

"개체 또는 불완전한 형태의 포인터를 다른 오브젝트 또는 불완전한 형태의 포인터로 변환 될 수있다 얻어진 포인터를 정확하게 지적위한 (57)으로 정렬되어 있지 않으면 - 유형을 지정하면 동작이 정의되지 않으며, 그렇지 않으면 다시 변환 될 때 결과는 원래 포인터와 동일하게 비교됩니다.

개체에 대한 포인터가 문자 형식에 대한 포인터로 변환되면 결과는 개체의 가장 낮은 주소 바이트를 가리 킵니다. 객체의 크기까지 결과의 연속적인 증분은 객체의 나머지 바이트에 포인터를 생성합니다. "0123"를 참조하십시오. "올바르게 정렬되었습니다"라는 개념은 일반적으로 포인터가 타입 A에 대한 포인터가 정확하게 타입 C에 대한 포인터에 대해 정렬 된 타입 B에 대한 포인터에 대해 올바로 정렬되면 타입 A에 대한 포인터는 타입 C에 대한 포인터에 대해 올바르게 정렬됩니다. "

0

약간의 질문에 혼란스러워하지만 두 번째와 세 번째 예제에서는 객체의 유형 (예제에서는 int)을 가진 lvalue를 통해 int에 액세스합니다.

C++ 3.10/15는 "객체의 동적 유형"유형을 가진 lvalue를 통해 객체에 액세스하는 것은 괜찮습니다.

나는이 질문에서 무엇을 잘못 생각합니까?

+0

int a [1];에서'a [0] = 0;을 할 때 두 개의 객체의 저장된 값을 변경합니다. 첫 번째 유형은'int' 유형이고, 두 번째 유형은'int [1 ]' 유형입니다. 또 다른 예로'struct A {int a; };'우리가 할 때'A a; a.a = 0;'두 객체의 저장된 값을 변경합니다. 첫 번째 객체는 'int'유형이고 두 번째 객체는 'A' 유형입니다. 우리가 반대 방향 (엘리먼트 또는 멤버를 총 lvalue로 변경할 수 있음)으로 변경할 수있는 앨리어싱 규칙이 있지만이 방향으로는 존재하지 않습니다. 그것이 내가 구하는 것이 의미하는 바입니다. –

+0

@Johannes : 나는 지금 질문을 이해한다고 생각한다. (그러나 여전히 확실하지 않다.) 그러나 표준에서 모호성은 여전히 ​​없습니다. 'a [0] = 0' (또는'aa = 0')은 동적 유형 ('int')을 통해 lvalue에 액세스하므로 잘 정의 된 동작입니다. 'struct A') 타입은 (표준의 추상 머신 정의로 인해) 업데이트 된 값을 반영해야합니다. –