Встроенный MemCpy Chk всегда будет переполнять целевой буфер
Обновление моего приложения с 32-разрядного до 64-разрядного.
Согласно документации Apple, значения с плавающей запятой имеют размер всего 4 байта, и мне нужно использовать CGFloat (8 байт).
Я использую memcpy
читать в байтах. Я обновил все мои sizeof(float)
с sizeof(CGFloat)
,
Но когда я получаю семантическую проблему
__builtin___memcpy_chk всегда будет переполнять целевой буфер. Развернуто из макроса
memcpy
Я обновил свой NSData readDataOfLenght
принять sizeof(CGFloat)
и, кажется, работает нормально. Иногда не все данные, которые считываются, верны.
Я боюсь, что я над головой в этом и мог бы использовать некоторую помощь.
-(void) readByteData:(NSFileHandle *)fHandle Size:(NSInteger)byteSize
{
[super readByteData:fHandle Size:byteSize];
NSData *data = [fHandle readDataOfLength:sizeof(CGFloat)];
float r;
memcpy(&r, [data bytes], sizeof(CGFloat));
self.radius = r;
int nCGPointSize = sizeof(CGFloat) * 2;
data = [fHandle readDataOfLength:nCGPointSize];
float xy[2];
memcpy(xy, [data bytes], nCGPointSize);
self.centerPos = ccp(xy[0], xy[1]);
data = [fHandle readDataOfLength:sizeof(CGFloat)];
float start_angle;
memcpy(&start_angle, [data bytes], sizeof(CGFloat));
self.startAngle = start_angle;
data = [fHandle readDataOfLength:sizeof(CGFloat)];
float end_angle;
memcpy(&end_angle, [data bytes], sizeof(CGFloat));
self.endAngle = end_angle;
data = [fHandle readDataOfLength:sizeof(int)];
int d;
memcpy(&d, [data bytes], sizeof(int));
self.dir = d;
flagClosed = YES;
}
1 ответ
Эта инструкция:
float r;
memcpy(&r, [data bytes], sizeof(CGFloat));
Сообщает вашему компилятору:
Читать
sizeof(CGFloat)
(== 8 байт!) С места[data bytes]
и напишите ихr
Но r
только 4 байта в размере! Итак, первые 4 байта записаны r
и следующие 4 байта записываются в следующие r
в памяти и это не допускается. memcpy
это простая инструкция копирования байтов, она перемещает любое количество байтов из области памяти A в область памяти B, она не может преобразовывать типы данных для вас. Если вам нужно конвертировать CGFloat
значения для float
значения, то вам действительно нужно сделать это преобразование самостоятельно.
CGFloat bigR;
memcpy(&bigR, [data bytes], sizeof(bigR));
self.radius = (float)bigR;
То же самое при чтении нескольких значений:
CGFloat bigXY[2];
data = [fHandle readDataOfLength:sizeof(bigXY)];
memcpy(bigXY, [data bytes], sizeof(bigXY));
self.centerPos = ccp((float)bigXY[0], (float)bixXY[1]);
Приведение приведено только для того, чтобы сделать более понятным, где происходит преобразование, большинство компиляторов также скомпилируют код без всех (float)
бросает и не жалуется.
Как общее правило:
memcpy(dst, src, size)
size
никогда не должен быть больше памяти src
указывает на или память dst
указывает на. В твоем случае, size
всегда был больше, чем память dst
указал на.
Пока объяснение, почему ваш код не работает. Тем не менее, вам на самом деле не нужно использовать memcpy
В любом случае, если у вас есть блок памяти из нескольких значений известного типа данных, конечно, вы можете напрямую обращаться к этой памяти, не копируя ее куда-либо:
NSData * data = [fHandle readDataOfLength:sizeof(CGFloat)];
if (!data) {
// ... handle errorr ...
}
const CGFloat * cgfloatsInData = (const CGFloat *)[data bytes];
self.radius = (float)cgfloatsInData[0];
data = [fHandle readDataOfLength:sizeof(CGFloat) * 2];
if (!data) {
// ... handle errorr ...
}
const CGFloat * cgfloatsInData = (const CGFloat *)[data bytes];
self.centerPos = ccp((float)cgfloatsInData[0], (float)cgfloatsInData[1]);
И так далее. Но это крайне неэффективно, так как вы, похоже, всегда ожидаете какую-то структуру фиксированного размера без дополнительных значений, так почему бы не прочитать ее как структуру? Таким образом, вам нужен только один доступ ввода / вывода, чтобы прочитать все это и только один NSData
объект должен быть создан системой.
const struct {
CGFloat radius;
CGFloat xCoord;
CGFloat yCoord;
CGFloat startAngle;
CGFloat endAngle;
int dir;
} __attribute__((packed)) * entry;
// `const` as the memory `entry` will point to will be read-only.
// `* entry` means entry is a pointer to memory of a struct
// that looks as described above. __attribute__((packed)) means
// the memory must be laid out exactly as shown above and have no
// padding for better alignment of fields.
NSData * data = [fHandle readDataOfLength:sizeof(*entry)];
// `sizeof(*entry)` means the size of the memory entry points to,
// contrary to `sizeof(entry)` which would be the size of entry itself
// and that would simply be the size of a pointer on your system, 8 bytes,
// whereas `sizeof(*entry)` will be 44 bytes.
entry = (const void *)dataBytes;
// Any pointer type can be cased to `void *` and assigning
// a `void *` pointer so some pointer is always allowed by the compiler.
self.radius = (float)entry->radius;
self.centerPos = ccp((float)entry->xCoord, (float)entry->yCoord);
self.startAngle = (float)entry->startAngle;
self.endAngle = (float)entry->endAngle;
self.dir = entry->dir;