C++ 방식으로 앨리어싱 구조 및 배열
ISOC 이전 시대에는 다음과 같은 코드가 아무도 놀라게 하지 않았을 것입니다.
struct Point {
double x;
double y;
double z;
};
double dist(struct Point *p1, struct Point *p2) {
double d2 = 0;
double *coord1 = &p1->x;
double *coord2 = &p2->x;
int i;
for (i=0; i<3; i++) {
double d = coord2[i] - coord1[i]; // THE problem
d2 += d * d;
}
return sqrt(d2);
}
유감스럽게도 이 문제의 행은 포인터 산술(p[i]
정의상 존재하기 *(p + i))
표준에서 명시적으로 허용되지 않는 배열의 외부에 있습니다.C++17을 위한 초안 4659는 8.7 [expr.add]에서 다음과 같이 말합니다.
식 P가 n개의 요소를 가진 배열 객체 x의 요소 x[i]를 가리키면, 식 P + J와 J + P(J는 j 값을 가진다)는 0 <= i + j <= n인 경우, (possibly hypot적인) 요소 x[i + j]를 가리키고, 그렇지 않으면 동작이 정의되지 않습니다.
그리고 (비규범적) 노트 86은 이를 더욱 명확하게 합니다.
배열 요소가 아닌 개체는 단일 요소 배열에 속하는 것으로 간주됩니다.n개 요소의 배열 x의 마지막 요소를 지나는 포인터는 이 목적을 위해 가상 요소 x[n]에 대한 포인터와 동일한 것으로 간주됩니다.
참고한 문항의 정답은 C언어가 조합을 통한 유형 펀닝을 수용한다는 점을 이용한 것이지만, C++ 표준에서는 결코 동등한 것을 찾을 수 없었습니다.그래서 저는 익명의 구조 구성원과 배열을 포함한 조합이Undefined Behaviour
C++—서로 다른 언어입니다...
질문:.
구조의 멤버를 C++에서 배열의 멤버인 것처럼 반복하는 적합한 방법은 무엇입니까?현재 (C++17) 버전에서 방법을 찾고 있지만 이전 버전의 솔루션도 환영합니다.
면책 사항:
분명히 같은 유형의 요소에만 적용되며 패딩은 간단한 방법으로 감지할 수 있습니다.assert
다른 질문에서 보듯 패딩, 얼라인먼트, 혼합형은 여기서 내 문제가 아닙니다.
멤버 간 포인터의 constexpr 배열을 사용합니다.
#include <math.h>
struct Point {
double x;
double y;
double z;
};
double dist(struct Point *p1, struct Point *p2) {
constexpr double Point::* coords[3] = {&Point::x, &Point::y, &Point::z};
double d2 = 0;
for (int i=0; i<3; i++) {
double d = p1->*coords[i] - p2->*coords[i];
d2 += d * d;
}
return sqrt(d2);
}
가장 쉬운 방법은 바로 구현하는 것입니다.operator[]
. 이런 도우미 배열을 만들 수도 있고 스위치를 만들 수도 있고...
struct Point
{
double const& operator[] (std::size_t i) const
{
const std::array coords {&x, &y, &z};
return *coords[i];
}
double& operator[] (std::size_t i)
{
const std::array coords {&x, &y, &z};
return *coords[i];
}
double x;
double y;
double z;
};
int main()
{
Point p {1, 2, 3};
std::cout << p[2] - p[1];
return 0;
}
struct Point {
double x;
double y;
double z;
double& operator[]( std::size_t i ) {
auto self = reinterpret_cast<uintptr_t>( this );
auto v = self+i*sizeof(double);
return *reinterpret_cast<double*>(v);
}
double const& operator[]( std::size_t i ) const {
auto self = reinterpret_cast<uintptr_t>( this );
auto v = self+i*sizeof(double);
return *reinterpret_cast<double const*>(v);
}
};
이것은 그 사이에 포장이 없다는 것에 의존합니다.double
당신의 struct에 s.그것을 주장하는 것은 어렵습니다.
POD 구조는 보장된 바이트 시퀀스입니다.
컴파일러는 컴파일할 수 있어야 합니다.[]
원시 배열 액세스 또는 포인터 산술과 동일한 명령(또는 그 결여)까지.이 최적화 작업이 "너무 늦게" 수행되어 다른 최적화 작업이 수행되지 않는 문제가 있을 수 있으므로 성능에 민감한 코드를 다시 확인하십시오.
로 하는 것은 합니다.char*
아니면std::byte*
uintptr_t
유효하겠지만, 이 경우 포인터 산술이 허용되는지에 대한 핵심 문제가 있습니다.
에 할 수 .intptr_t
산술을 한 다음 값을 포인터 유형으로 다시 캐스팅하는 것이 구현 정의된 동작입니다.대부분의 컴파일러에서 작동할 것으로 생각합니다.
template<class T>
T* increment_pointer(T* a){
return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(a)+sizeof(T));
}
이 기술은 가장 효율적이며, 한 사용자가 테이블을 찾아보면 최적의 최적화 장치를 만들 수 없을 것 같습니다. 어셈블리-비교
언급URL : https://stackoverflow.com/questions/48463521/aliasing-struct-and-array-the-c-way
'bestsource' 카테고리의 다른 글
XML 스키마(XSD) 검증 도구? (0) | 2023.10.16 |
---|---|
페이지를 다시 로드한 후 트위터 부트스트랩으로 현재 탭을 활성화하려면 어떻게 해야 합니까? (0) | 2023.10.16 |
사용자 지정 워드프레스 편집기? (0) | 2023.10.16 |
Angular-ui.router:보기 새로 고침 없이 URL 업데이트 (0) | 2023.10.16 |
브라우저 크기가 조정되면 jqGrid 크기 조정? (0) | 2023.10.16 |