2014-12-12 3 views
-1

동적 배열의 이진 파일에 쓰려고합니다.C++ 동적 배열을 파일에 쓸 수 없습니다.

여기 내 코드입니다 :

FILE* file; 
std::ofstream outStream; 

file = fopen("mesh1.model", "w"); 
outStream = std::ofstream(file); 

unsigned numTriangles; 
float *vertices; 
float *uvs; 

unsigned degree = 0; 

numTriangles = 2 * std::pow(4, degree); // numTriangles == 2 in this case 

vertices = new float[9 * numTriangles]; 
uvs = new float[6 * numTriangles]; 

vertices[0] = -1.0f; 
vertices[1] = 0.0f; 
vertices[2] = 1.0f; 

uvs[0] = 0.0f; 
uvs[1] = 0.0f; 

[....] 

vertices[15] = 1.0f; 
vertices[16] = 0.0f; 
vertices[17] = -1.0f; 

uvs[10] = 1.0f; 
uvs[11] = 1.0f; 

outStream.write((const char*)numTriangles, sizeof(numTriangles)); 
// Get runtime error on the line after this comment [access violation] (VS2013) 
outStream.write((const char*)&(vertices), sizeof(float) * 9 * numTriangles); 
outStream.write((const char*)&(uvs), sizeof(float) * 6 * numTriangles); 

delete[] vertices; 
delete[] uvs; 

fclose(file); 
file = fopen("mesh1.model", "r"); 

내가 유사한 문제와 과거의 코멘트를 보았다,하지만 그들은 도움이되지 않았다.

그들 중 한 명은 시도했지만 도움이되지 않은 reinterpret_cast을 사용했습니다.

답변

1

을 당신의 범죄자는 다음과 같습니다.

outStream.write((const char*)numTriangles, sizeof(numTriangles)); 

첫 번째 매개 변수는 데이터 자체가 아닌 쓸 데이터!
데이터를 예상 된 포인터로 캐스팅하면 컴파일러가 종료되지만 불필요한 읽기 액세스 인 가비지 또는 코어 덤프가 생성됩니다.

당신은 대신 같은 것을 사용 할 수 있습니다 : 당신이 그대로 C++ 충분히 상세하지 생각하지 않는

outStream.write((const char *) & numTriangles, sizeof(numTriangles)); 

reinterpret_cast이 정말 필요가 없습니다.

ofstream은 스트림 인터페이스에서 잘 작동합니다. 즉, << 연산자 오버로드를 활용하여 개체의 텍스트 표현을 파일에 넣을 때 유용합니다.

순수한 이진수를 쓰려면 ofstream이 투명한 const void * 포인터를 제공하지 않으므로 쓰려고하는 모든 단일 데이터 블록을 캐스팅해야하기 때문에 단지 두려워 할뿐입니다.

어쨌든 fopen으로 시작했기 때문에 제게는 STDIO를 사용하고 fwrite을 사용하는 것이 좋습니다. 훨씬 적게 장황하고 작업도 마찬가지입니다.

편집 : cdhowie는 모든 종류의 문제가 발생할 수 있습니다 이진 데이터의 원시 블록을 기록, 지적이 모든 말했다되고

.

unsigned이 다른 크기 인 다른 플랫폼 (예 : x32 대신 x64를 구축하는 것처럼 간단 함)에서 코드를 다시 컴파일한다고 가정합니다. 새로 컴파일 된 실행 파일이 읽으려고 할 때 데이터의 내용은 어떻게됩니까?

지속적인 코드를 작성하려는 경우 최소한 이진 이진 표현과 관계없는 값 (최소한 고정 된 크기의 정수 및 부동 소수점 수 및 엔디안 손질).

또 다른 해결책은 텍스트 데이터를 작성하고 gzip과 같은 전용 라이브러리로 압축하는 것입니다. 그러면 문자 데이터 형식으로 개체를 작성하는 철학을 활용할 수도 있습니다.

+0

'reinterpret_cast'는 필요하지 않지만 둘 다'std :: unique_ptr'입니다. 우리는 우리 자신의 기억을 관리 할만큼 똑똑 하죠? ... 어쩌면,하지만 우리는 이러한 기능을 사용합니다. 왜냐하면 더 장황한 대안 인 것보다 * 더 안전하기 때문입니다. C 스타일의 캐스트를 사용하면 기대하지 않았던 방식으로 캐스팅을 결정할 때 모든 종류의 문제가 발생할 수 있습니다 (https://anteru.net/2007/12/18/200/). C++ 스타일의 캐스트를 사용하면 캐스트로 러시아어 룰렛을 연주하는 대신 원하는 유형의 캐스트를 정확하게 지정할 수 있습니다. 더 안전하고 놀라움이 적기 때문에 더 좋습니다. – cdhowie

+0

감사합니다.이 방법이 효과가 있으며 fwrite를 시도해 보겠습니다. – MichaelMitchell

+0

@cdhowie'ofstream' 바이트 블록 쓰기 인터페이스는 여기서 러시아어 룰렛을 재생하는 인터페이스입니다. 문제는 내가 작성한 데이터를 깔끔하게 재 해석하거나 단순히 C 스타일로 캐스팅했는지 여부가 아닙니다. 중요한 점은 데이터와 크기가 일관성이 있는지 확인해야한다는 것입니다. 이는 인터페이스의 개념적 약점입니다. 여러분은 적어도 작성된 객체의 크기를 계산하는 인터페이스와 다중 사본을 작성하는 추가 선택 매개 변수를 기대할 수 있었지만'ofstream'은'fwrite'보다 낫지 않고 불필요한 쓸모없는 잡동사니를 추가했습니다. –

0

write() 번의 세 가지 호출이 모두 잘못되었습니다. 그러나 우리가 그것에 들어가기 전에, 우리가 방해가되지 않게해야 할 것이 하나 있습니다 :

C++에서 C 스타일 캐스트를 절대로 사용하지 마십시오.

C++에는보다 구체적인 캐스트 연산자가 있으므로 항상 사용해야합니다. 이 경우 reinterpret_cast을 사용하려고합니다.

첫 번째 경우는 포인터가 아닌 포인터를 캐스팅하기 때문에 잘못되었습니다. 대신 numTriangles에 대한 포인터를 가져야합니다. 다른 두 경우

outStream.write((const char*)numTriangles, sizeof(numTriangles)); 

// Should be this: 

outStream.write(reinterpret_cast<const char *>(&numTriangles), sizeof(numTriangles)); 

, verticesuvs는, 그래서 여기에 이미 저장하고자하는 데이터에 대한 포인터와 포인트 당신이 & 연산자를 사용해서는 안 : 여기

outStream.write((const char*)&(vertices), sizeof(float) * 9 * numTriangles); 
outStream.write((const char*)&(uvs), sizeof(float) * 6 * numTriangles); 

// Should be this: 

outStream.write(reinterpret_cast<const char *>(vertices), sizeof(float) * 9 * numTriangles); 
outStream.write(reinterpret_cast<const char *>(uvs), sizeof(float) * 6 * numTriangles); 
+0

여기 실제 문제는 문자에 대한 포인터를 사용하도록하는 '쓰레기'인터페이스의 엉성한 것입니다. 12 개의 서로 다른 항목을 작성하는 함수는 기능상 불필요한 캐스트로 비대 해져서 코드의 관련 부분 (실제로 작성된 데이터의 이름과 크기)을 장황한'reinterpret_cast'의 혼란에 숨 깁니다. 게다가 여기에서 진짜 위험한 것은 주소와 크기 사이에 불일치가있는 것인데, 이는 'ofstream'과'fwrite'와 똑같이 존재합니다. 불충분 한'ofstream'을 삭제하고 직접 주소 사용을 허용하는'fwrite'와 같은 또 다른 인터페이스를 사용하는 것이 좋습니다. –

+0

@kuroineko 글쎄, 더 나은 솔루션은 적절한 데이터 직렬화, 원시 메모리 블록을 작성하지 않을 것입니다. 다른 엔디안 또는 다른 패딩 요구 사항을 가진 아키텍처에서이 데이터를로드하면 모든 것이 터집니다. 'fwrite()'는 OP가하는 것과 기능적으로 동일하다; 문법은 좀 더 좋을 수도 있지만 그게 전부입니다. – cdhowie

+0

더 동의 할 수는 없지만 아키텍처 변경을 제안하면 원래 질문의 범위를 벗어납니다. :) –

관련 문제