Sorry for my newbie question. Please refrain from down voting me because I am learning C. I am an experienced programmer on other languages, but not on C. I am trying to learn C at the same time I am trying to understand a library for iOS called Novaine, on Github.
This library has a module with the following signature:
Novocaine *audioManager = [Novocaine audioManager];
[audioManager setInputBlock:^(float *newAudio, UInt32 numSamples, UInt32 numChannels) {
}];
So, the internal block is receiving numSamples, numChannels and newAudio and newAudio is of kind float pointer?
What kind of object is this? an array of floats? if this is an array, how do I access its values? How do I know the number of elements it has?
This is a pointer to float value. Nothing strange here. It is often use to point some area in memory. You don't know the size of this are. Might be a single float but also can be larger, continuous space in memory.
You don't know what type of object is stored there. float doesn't mean that floats are stored there. It could be declared as void * as well. Again, it is just a space in memory. By typing float * you just give the compile a hint that when you move newAudio pointer (doing or example newAudio ++) it will move a pointer by a sizeof(float) number of bytes.
Based on method fingerprint I assume that this is a pointer to the first element of some buffer which size is probably numSamples * numChannels * size of single sample
This part of memory should be allocated first, to make sure that it's reserved for you:
float *newAudio = calloc(numSamples * numChannels, sizeof(float));
Related
I've taken a look at several other questions that all deal with this error, but all of the answers basically just say "don't do pointer math". The code I have is as follows:
MyObject * __strong * array = (MyObject * __strong *)calloc(sizeof(MyObject*), 5);
array[0] += 4;
I want to know why I can't do pointer math. According to the error, the MyObject* values that are pointed to are of different sizes, but that shouldn't matter, right? It's just an array of pointers - who cares how big the stuff they point to is?
I'm guessing I probably just don't understand all the nuances of ARC.
Your variable "array" is a pointer to a pointer and yes, you can consider it as an array of pointers. The size of your object "MyObject" is not constant obviously and the compiler is right not allowing you do such operation.
It is not clear what your wanted to do with your variable.
array[0] += 4;
Takes "MyObject *" from the first element of your array and want to add to it offset of 4, but to calculate such offset compilers wants to know the size of the object.
May be you wanted to do something like
array = array + 4;
or
array += 4;
I've got a question about what I think boils down to C syntax and memory considerations. I have a callback in an Objective-C class that processes some audio, and one of the arguments is bufferListInOut. It represents a mono audio signal that I'd like to convert to stereo. Here's my code:
static void tap_ProcessCallback(MTAudioProcessingTapRef tap,
CMItemCount numberFrames,
MTAudioProcessingTapFlags flags,
AudioBufferList *bufferListInOut,
CMItemCount *numberFramesOut,
MTAudioProcessingTapFlags *flagsOut){
// Retrieve mono audio data into bufferListInOut
MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, NULL, NULL, NULL);
// Copy the mono channel's data
float *channelLeft = malloc(numberFrames * sizeof(float));
channelLeft = bufferListInOut->mBuffers[0].mData;
// Attempt to create a second channel which is (currently) a copy of the first
bufferListInOut->mNumberBuffers = 2; // 2 for stereo, 1 for mono
bufferListInOut->mBuffers[1].mNumberChannels = 1;
bufferListInOut->mBuffers[1].mDataByteSize = numberFrames * sizeof(Float32);
bufferListInOut->mBuffers[1].mData = channelLeft;
// Set number of frames out
*numberFramesOut = numberFrames;
}
Some notes:
In this code, the new channel is just a copy of the original, but in practice it will undergo some processing.
The naming is a little weird, but mNumberBuffers is indeed meant to be 2 and mNumberChannels is meant to be 1.
This crashes with an EXC_BAD_ACCESS error on a rendering thread down the line. So, my question is what is the right way to add a new buffer to this struct? I don't delve into C too often, so I'm sure I'm missing some basics here. Any pointers on this would be great. Thanks for reading.
You cannot do what you are attempting, at least in the way you are trying to do it. The type AudioBufferList is declared as:
struct AudioBufferList { UInt32 mNumberBuffers; AudioBuffer mBuffers[1]; };
This is a classic C pattern for a variable sized struct. To create a struct for N buffers a single block of memory is allocated with the size:
sizeof(UInt32) + N * sizeof(AudioBuffer)
The address of that block is assigned to a AudioBufferList * variable and the field mNumberBuffers set to N. You cannot simply increase the mNumberBuffers to increase the size of the array, instead you must either allocate a new complete struct, or realloc the existing one - realloc increases the size of memory block if possible or allocates a new one and copies the existing data into it if not.
Given your tap_ProcessCallback() function is passed a AudioBuuferList * value and does not return one, there is no way it can change the size of the struct (i.e. the number of buffers) it is passed.
As pointed out in comments you are also doing pointer assignment when you intend to copy memory - see memcpy and friends.
So you need a redesign - your goal is possible, just not how and where you've attempted it.
HTH
Out of pure curiosity, I started playing with array's in ways that I have never used before. I tried making a data structure array, and set it equal to another:
typedef struct _test {
float value;
} test;
Simple enough struct, so I tried this:
test struct1[10];
test struct2[20];
struct1 = struct2;
I didn't think this would work, and it didn't even compile. But, this interests me a lot. Is it possible to take an array of 10 and increase the size to 20, while copying the data?
Objective-C
I am actually doing this with Objective-C, so I'd like to hear from the Objective-C people as well. I want to see if it is possible to change the size of struct1 in this file.
#interface Object : NSObject {
test struct1;
}
Remember: This is only out of curiosity, so everything is open to discussion.
Something else that is not exactly pertinent to your question but is interesting nonetheless, is that although arrays cannot be assigned to, structs containing arrays can be assigned to:
struct test
{
float someArray[100];
};
struct test s1 = { /* initialise with some data*/ };
struct test s2 = { /* initialise with some other data */ };
s1 = s2; /* s1's array now contains contents of s2's array */
This also makes it possible to return fixed-length arrays of data from functions (since returning plain arrays is not allowed):
struct test FunctionThatGenerates100Floats(void)
{
struct test result;
for (int i = 0; i < 100; i++)
result.someArray[i] = randomfloat();
return result;
}
As others have said, arrays allocated like that are static, and can not be resized. You have to use pointers (allocating the array with malloc or calloc) to have a resizable array, and then you can use realloc. You must use free to get rid of it (else you'll leak memory). In C99, your array size can be calculated at runtime when its allocated (in C89, its size had to be calculated at compile time), but can't be changed after allocation. In C++, you should use std::vector. I suspect Objective-C has something like C++'s vector.
But if you want to copy data between one array and another in C, use memcpy:
/* void *memcpy(void *dest, const void *src, size_t n)
note that the arrays must not overlap; use memmove if they do */
memcpy(&struct1, &struct2, sizeof(struct1));
That'll only copy the first ten elements, of course, since struct1 is only ten elements long. You could copy the last ten (for example) by changing &struct2 to struct2+10 or &(struct2[10]). In C, of course, not running off the end of the array is your responsibility: memcpy does not check.
You can also you the obvious for loop, but memcpy will often be faster (and should never be slower). This is because the compiler can take advantage of every trick it knows (e.g., it may know how to copy your data 16 bytes at a time, even if each element is only 1 byte wide)
You can't do this in C with static arrays, but you can do it with dynamically allocated arrays. E.g.,
float *struct1, *struct2, *struct3;
if(!(struct1 = malloc(10 * sizeof(float))) {
// there was an error, handle it here
}
if(!(struct2 = realloc(struct1, 20 * sizeof(float))) {
// there was an error, handle it here
// struct1 will still be valid
}
if(!(struct3 = reallocf(struct2, 40 * sizeof(float))) {
// there was an error, handle it here
// struct2 has been free'd
}
In C, I believe that's a good place to use the realloc function. However, it will only work with dynamically allocated arrays. There's no way to change the memory allocated to struct1 by the declaration test struct1[10];.
In C arrays are constants, you can't change their value (that is, their address) at all, and you can't resize them.
Clearly if you declare your array with a fixed size, test struct1[10] then it cannot be resized. What you need to do is to declare it as a pointer:
test *struct1;
Then you must use malloc to allocate the array and can use realloc to resize it whilst preserving the contents of the original array.
struct1 = malloc(10*sizeof(*struct1));
//initialize struct1 ...
test *struct2 = realloc(struct1, 20*sizeof(*struct1));
If you're using Objective C, you know you can just use NSMutableArray, which automatically does the realloc trick to reallocate itself to store however many objects you put in it, up the limit of your memory.
But you're trying to do this with struct? What would that even mean? Suppose you increase the amount of memory available to struct1 in Object. It's still a struct with one member, and doesn't do anything more.
Is the idea to make Object be able to contain an expanded struct?
typedef struct _test2 {
float value;
NSObject *reference;
} test2;
But then you still can't access reference normally, because it's not a known part of Object.
Object *object2;
...
NSLog(#"%#", object2.struct1.reference); // does not compile
If you knew you had one of your modified objects, you could do
Object *object2;
...
NSLog(#"%#", ((test2)(object2.struct1)).reference);
And also you could still presumably pass object2 to anything that expects an Object. It only has any chance of working if struct1 is the last member of Object, and don't mess with subclassing Object either.
Some variety of realloc trick might then work, but I don't think realloc in particular, because that's intended to be used on objects that are allocated with malloc, and the details of what C function is used to allocate objects in not exposed in Objective C, so you shouldn't assume it's malloc. If you override alloc then you might be able to make sure malloc is used.
Also you have to watch out for the fact that it's common in Objective C for more than one pointer to an object to exist. realloc might move an object, which won't be semantically correct unless you correct all the pointers.
I'm having a issue getting the size of a struct pointer after allocating the memory using malloc or realloc. I've worked around this by keeping track of the memory in a separate counter, but I would like to know if this is a bug or if there is a way to properly query the size of a struct pointer.
Sample code demonstrates that no matter how much memory I allocate to the struct pointer it always returns 4 when querying using the sizeof() method.
typedef struct {
int modelID;
int bufferPosition;
int bufferSize;
} Model;
Model *models = malloc(10000 * sizeof(Model));
NSLog(#"sizeof(models) = %lu", sizeof(models)); //this prints: sizeof(models) = 4
4 is the correct answer, because "models" is a pointer, and pointers are 4 bytes. You will not be able to find the length of an array this way. Any reason you're not using NSArray?
If I understand you correctly you want to get at the size of the allocated buffer.
sizeof if the wrong way to go since it is evaluated at compile time. The size of the buffer is a runtime concept.
You would need a way to query you C library to return the allocation size for the pointer to the buffer.
Some systems have a way to get that kind of information, for instance malloc_size on Mac OS.
4 is the correct answer.
Pointers point to a memory location which could contain anything. When you are querying the size of a pointer, it gives the size of the memory location which holds the pointer, which in your case is 4.
For example
int *a = pointing to some large number;
int *b = pointing to a single digit number;
In the above case, both a and b have the same size irrespective of where they are pointing to.
For more information, have a look at this post size of a pointer
sizeof(myvar) will return size of pointer. in 32bit environment it equals to 4(bytes).
why don't you use sizeof (Model) instead?
I'm working with Objective-C and I need to add int's from a NSArray to a NSMutableData (I'm preparing a to send the data over a connection). If I wrap the int's with NSNumber and then add them to NSMutableData, how would I find out how many bytes are in the NSNumber int? Would it be possible to use sizeof() since according to the apple documentation, "NSNumber is a subclass of NSValue that offers a value as any C scalar (numeric) type."?
Example:
NSNumber *numero = [[NSNumber alloc] initWithInt:5];
NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];
[data appendBytes:numero length:sizeof(numero)];
numero is not a numeric value, it is a pointer to a an object represting a numeric value. What you are trying to do won't work, the size will always be equal to a pointer (4 for 32 bit platforms and 8 for 64 bit), and you will append some garbage pointer value to your data as opposed to the number.
Even if you were to try to dereference it, you cannot directly access the bytes backing an NSNumber and expect it to work. What is going on is an internal implementation detail, and may vary from release to release, or even between different configurations of the same release (32 bit vs 64 bit, iPhone vs Mac OS X, arm vs i386 vs PPC). Just packing up the bytes and sending them over the wire may result in something that does not deserialize properly on the other side, even if you managed to get to the actual data.
You really need to come up with an encoding of an integer you can put into your data and then pack and unpack the NSNumbers into that. Something like:
NSNumber *myNumber = ... //(get a value somehow)
int32_t myInteger = [myNumber integerValue]; //Get the integerValue out of the number
int32_t networkInteger = htonl(myInteger); //Convert the integer to network endian
[data appendBytes:&networkInteger sizeof(networkInteger)]; //stuff it into the data
On the receiving side you then grab out the integer and recreate an NSNumber with numberWithInteger: after using ntohl to convert it to native host format.
It may require a bit more work if you are trying to send minimal representations, etc.
The other option is to use an NSCoder subclass and tell the NSNumber to encode itself using your coder, since that will be platform neutral, but it may be overkill for what you are trying to do.
First, NSNumber *numero is "A pointer to a NSNumber type", and the NSNumber type is an Objective-C object. In general, unless specifically stated somewhere in the documentation, the rule of thumb in object-oriented programming is that "The internal details of how an object chooses to represent its internal state is private to the objects implementation, and should be treated as a black box." Again, unless the documentation says you can do otherwise, you can't assume that NSNumber is using a C primitive type of int to store the int value you gave it.
The following is a rough approximation of what's going on 'behind the scenes' when you appendBytes:numero:
typedef struct {
Class isa;
double dbl;
long long ll;
} NSNumber;
NSNumber *numero = malloc(sizeof(NSNumber));
memset(numero, 0, sizeof(NSNumber));
numero->isa = objc_getClass("NSNumber");
void *bytes = malloc(1024);
memcpy(bytes, numero, sizeof(numero)); // sizeof(numero) == sizeof(void *)
This makes it a bit more clear that what you're appending to the NSMutableData object data is the first four bytes of what ever numero is pointing to (which, for an object in Obj-C is always isa, the objects class). I suspect what you "wanted" to do was copy the pointer to the instantiated object (the value of numero), in which case you should have used &numero. This is a problem if you're using GC as the buffer used by NSMutableData is not scanned (ie, the GC system will no longer "see" the object and reclaim it, which is pretty much a guarantee for a random crash at some later point.)
It's hopefully obvious that even if you put the pointer to the instantiated NSNumber object in to data, that pointer only has meaning in the context of the process that created it. A pointer to that object is even less meaningful if you send that pointer to another computer- the receiving computer has no (practical, trivial) way to read the memory that the pointer points to in the sending computer.
Since you seem to be having problems with this part of the process, let me make a recommendation that will save you countless hours of debugging some extremely difficult implementation bugs you're bound to run in to:
Abandon this entire idea of trying to send raw binary data between machines and just send simple ASCII/UTF-8 formatted information between them.
If you think that this is some how going to be slow, or inefficient, then let me recommend that you bring every thing up using a simplified ASCII/UTF-8 stringified version first. Trust me, debugging raw binary data is no fun, and the ability to just NSLog(#"I got: %#", dataString) is worth its weight in gold when you're debugging your inevitable problems. Then, once everything has gelled, and you're confident that you don't need to make any more changes to what it is you need to exchange, "port" (for lack of a better word) that implementation to a binary only version if, and only if, profiling with Shark.app identifies it as a problem area. As a point of reference, these days I can scp a file between machines and saturate a gigabit link with the transfer. scp probably has to do about five thousand times as much processing per byte to compress and encrypt the data than this simple stringification all while transferring 80MB/sec. Yet on modern hardware this is barely enough to budge the CPU meter running in my menu bar.