Ok, trusting fread to do the right thing with my FILE pointer was the right thing to do. The next fread call did indeed start from where the last one left off. I was able to move past the first overall file header and read in the channel headers. Not only that, but I was able to use information in the file header (the channel count) to tell fread specifically how far into the file to go.
Another important lesson (or rather, putting into practice what I have already read about).
stdio.h speaks of fread as this...
extern size_t fread (void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __stream) __wur;
Now, I don't know what 100% means, but I know that the first thing fread wants is a memory address. It LOOKS LIKE it wants a pointer, but when your PROTOTYPE has the pointer to some type you need to be passing the function a memory address to that type.
So, I used fread for two things - getting the overall file header (where there is one of) and getting the channel headers (which there are several of).
The file header and channel headers are declared as follows:
struct PL_FileHeader fileheader;
struct PL_ChanHeader chanheader[128];
and when I used fread for each, I used it as follows:
fread(&fileheader, sizeof(struct PL_FileHeader), 1, plxfilepointer);
fread(chanheader, channelcount * sizeof(struct PL_ChanHeader), 1, plxfilepointer);
You'll see in the second fread things are a bit different. The first argument fread wants is the location of a variable (in my case a structure) for the data to go to. fileheader is a structure, so I passed fread the address with &fileheader. chanheader is actually an ARRAY of structures, so all I had to do is pass it the name of the array - a shortcut of sorts. I say a shortcut because I can also say &chanheader and it means the same thing. The second argument is how much to dig into the file. For the fileheader I just want to dig in the amount of size that the fileheader is. For the chanheader I needed to dig in, but only for as many channels as the fileheader says I have. That was an easy number to extract (channelcount) and multiplication took care of the rest. Yes, this means I have 124 elements of that array unused, but I'm not ready to dynamically allocate that just yet.
I'm 28 (oops, 29 now) and I want to be C literate by the time I'm 30. That's two (one) years to become competent at something I've been wanting to do nearly my whole life. No pressure.
Tuesday, December 28, 2010
wowie
Well, thinking more about global variables made me realize how overkill it was to be passing around my FILE pointer like I was doing. I moved the declaration to outside of main and now each function that needs it can just use it without needing it (or a reference to it) to be passed along.
That makes like... 15 of my hardest lessons in the past few months about passing pointers as function arguments completely unnecessary! They were useful lessons certainly, but it feels weird making my code much simpler and less complex when the complexity is what has gotten me this far.
I wonder if there is any harm in what I'm doing...
That makes like... 15 of my hardest lessons in the past few months about passing pointers as function arguments completely unnecessary! They were useful lessons certainly, but it feels weird making my code much simpler and less complex when the complexity is what has gotten me this far.
I wonder if there is any harm in what I'm doing...
rules about global variables
I ran into a weird problem where a function couldn't see a variable that I thought was considered global. Turns out I forgot that variables declared in main aren't considered global - just local to main. You have to declare them before main.
seek
Today's goal is to get my file pointer to the start of the interesting data.
The file header contains three numbers that I'll need - the number of DSP channels, the number of event channels, and the number of slow channels. Each one of these channels has its own corresponding header I have to skip over. I actually need data in some of those headers, but I think it will be easier to separate the two actions. I'll get the data I need from the headers, but then set the pointer back to the beginning and skip to the data block from there. That seems more straightforward than trying to know how far in I've gone and then jumping forward the correct amount.
Hmm, I just read through the example program and this seems to be what it does, also. It's hard to tell because again I'm not sure how much keeping track of things fread does.
The file header contains three numbers that I'll need - the number of DSP channels, the number of event channels, and the number of slow channels. Each one of these channels has its own corresponding header I have to skip over. I actually need data in some of those headers, but I think it will be easier to separate the two actions. I'll get the data I need from the headers, but then set the pointer back to the beginning and skip to the data block from there. That seems more straightforward than trying to know how far in I've gone and then jumping forward the correct amount.
Hmm, I just read through the example program and this seems to be what it does, also. It's hard to tell because again I'm not sure how much keeping track of things fread does.
Monday, December 27, 2010
about my tests
I think I'm forgetting that FILE really is something goofy....
More tests needed. More tests, more tests.
If I say:
FILE *fp;
Then I'm saying that fp holds a memory address to something that is FILE. But what is FILE?
I know what int and char are, but what is FILE?
If type FILE is a structure (I'm certain it must be) then what is it, and what do fopen and fread do to its members?
*EDIT*
Yea, maybe I should just consider the FILE thing as a "it's helpful don't worry about it" sort of business.
http://en.allexperts.com/q/C-1587/2008/5/FILE-Structure.htm
*EDIT X2*
I think I figured it out. My assertion from a few posts ago was wrong:
"I'll need to restate obvious things to work through this. My file pointer, plxfilepointer, is a variable that contains a memory address. This memory address is a location in memory where my file is being held (to the best of my knowledge that's how fopen works)."
What it should says is that my file pointer, plxfilepointer, is a variable that contains a memory address to a structure of type FILE that has all kinds of things inside for the standard library of file manipulation functions to deal with. De-referencing plxfilepointer makes no sense without intimate knowledge of the members of the structure.
Even K&R says to not worry too much about it and just let the functions do their job.
Ok, I feel better.
More tests needed. More tests, more tests.
If I say:
FILE *fp;
Then I'm saying that fp holds a memory address to something that is FILE. But what is FILE?
I know what int and char are, but what is FILE?
If type FILE is a structure (I'm certain it must be) then what is it, and what do fopen and fread do to its members?
*EDIT*
Yea, maybe I should just consider the FILE thing as a "it's helpful don't worry about it" sort of business.
http://en.allexperts.com/q/C-1587/2008/5/FILE-Structure.htm
*EDIT X2*
I think I figured it out. My assertion from a few posts ago was wrong:
"I'll need to restate obvious things to work through this. My file pointer, plxfilepointer, is a variable that contains a memory address. This memory address is a location in memory where my file is being held (to the best of my knowledge that's how fopen works)."
What it should says is that my file pointer, plxfilepointer, is a variable that contains a memory address to a structure of type FILE that has all kinds of things inside for the standard library of file manipulation functions to deal with. De-referencing plxfilepointer makes no sense without intimate knowledge of the members of the structure.
Even K&R says to not worry too much about it and just let the functions do their job.
Ok, I feel better.
ran some tests
The key here is that I'm trying to see evidence that the file pointer is moving after fread gets data.
I'll need to restate obvious things to work through this. My file pointer, plxfilepointer, is a variable that contains a memory address. This memory address is a location in memory where my file is being held (to the best of my knowledge that's how fopen works).
A memory address is just a number, and I figured that printing to screen this number before and after fread would do something interesting. It doesn't. It just prints the same number twice.
For kicks I decided to change the printf lines - instead of printing plxfilepointer, I printed *plxfilepointer. I de-referenced it such that I'm printing out whatever exists at the memory address that plxfilepointer points to. IF plxfilepointer isn't changing (it holds the same memory address before and after) then the de-referenced value shouldn't change, right? Well... that's not what I'm seeing.
Without de-referencing plxfilepointer I see this output:
File pointer is 760C2960
File pointer after fread 760C2960
I take this to be the memory address that plxfilepointer contains, which should the the memory address of the start of my file.
If I print out the de-referenced plxfilepointer, I get this:
File pointer is 00000000
File pointer after fread 00644830
I don't understand what this means. The "after fread" number is random, but the first pre-fread is always 00000000. I thought that the de-referenced file pointer would point to my file's location or the contents of the file - I still am not clear on what type FILE is. In either case the first number shouldn't be 0 (that's neither an address OR contents) or random (address maybe, contents no).
I'm growing convinced that there is something about FILE pointers and fread that are special that I need to not worry too much about.
more fread
K&R makes no mention of fread altering the file pointer, but it does mention fseek for this purpose.
That's ok, I guess. I'll just have to keep a variable around to hold how far into the file I am. Then I'll just have to do some pointer arithmetic in each fread call.
That's ok, I guess. I'll just have to keep a variable around to hold how far into the file I am. Then I'll just have to do some pointer arithmetic in each fread call.
Sunday, December 26, 2010
Come on, fread.
I can't get ahead in my program because I can't make fread perform as advertised.
Behold:
"Upon returning, fread sets the file pointer in the stream pointing to the byte past the last byte that has been read. "
This does not appear to be happening. My file pointer never gets offset after fread sucks in some data. This is very irritating because I don't want to have to do any more bookkeeping than necessary about how far into the file I am.
I'm going to have to strip down my program and tease out the behavior. My original thought was that fread was adding an offset to my local variable file pointer, instead of the one in main. Some cleverly placed printf statements for all concerned file pointers pre and post fread show that nothing is changed.
I have one other hunch that will be confirmed with a really simple program, but that will have to wait until later.
Behold:
"Upon returning, fread sets the file pointer in the stream pointing to the byte past the last byte that has been read. "
This does not appear to be happening. My file pointer never gets offset after fread sucks in some data. This is very irritating because I don't want to have to do any more bookkeeping than necessary about how far into the file I am.
I'm going to have to strip down my program and tease out the behavior. My original thought was that fread was adding an offset to my local variable file pointer, instead of the one in main. Some cleverly placed printf statements for all concerned file pointers pre and post fread show that nothing is changed.
I have one other hunch that will be confirmed with a really simple program, but that will have to wait until later.
Saturday, December 25, 2010
flu
I have the flu - confirmed with one of those rapid flu test things as influenza A. I went to one of those little clinics that some CVS pharmacies have. The last time I was there was when I had strep a few years ago.
Anyways, I'm so awfully behind in learning C. I had hoped to do something over the holidays but November and December have been dominated by family stuff and wedding planning (and now the flu).
I thought I was so clever getting my environment set up on my netbook, but switching my keyboard/mouse/monitor between my netbook and desktop is a hassle. Or maybe I'm just lazy.
I had two months of living alone which should have been perfect for focusing on programming, but all I did was work 12 hour days since I didn't have a reason to come home on time.
Well. Here's to 2011 being more productive.
Anyways, I'm so awfully behind in learning C. I had hoped to do something over the holidays but November and December have been dominated by family stuff and wedding planning (and now the flu).
I thought I was so clever getting my environment set up on my netbook, but switching my keyboard/mouse/monitor between my netbook and desktop is a hassle. Or maybe I'm just lazy.
I had two months of living alone which should have been perfect for focusing on programming, but all I did was work 12 hour days since I didn't have a reason to come home on time.
Well. Here's to 2011 being more productive.
Tuesday, December 14, 2010
more parameters
Since I don't have the ability to graph anything visually I should try to get out data that doesn't need it. Something like average inter-spike interval of units on a channel. This would require me to extract data, perform a calculation on it, and then present it. It wouldn't even be a lot of data - just unit classification (0 for unsorted, 1 for unit 1, 2 for unit 2, etc) and the corresponding timestamp. Should I put it in one big two dimensional array, or have an array for each unit? Would getting the average interval for each unit force me to run through that array once per unit? How could I make that more graceful? Perhaps I should be thankful that the units correspond to numbers. I could have a 27 element array (since there is a max of 26 units plus 0 for unsorted) and keep a running tab and using the unit classification as the index of the array I'm keeping the interval in.
Hmm...
Hmm...
Monday, December 13, 2010
parameters
I need to better define this program I'm writing. Trying to pad it out to be able to do anything is not working! I need a spec.
Friday, December 10, 2010
Error error
I haven't gotten behind a keyboard to get some coding in since last weekend.
Something embarrassing happened over the weekend while I was working on my program for reading files. When running the program through Code Blocks it would work great, but if I dropped to terminal and tried to run it I kept getting "file not found". I figured it was the terminal saying that it couldn't find my program and I spent about fifteen minutes fussing with permissions and checking to see what commands Code Blocks was doing that I wasn't when it finally dawned on me what was happening. "file not found" is the error message I wrote into the code for when it couldn't find my test file.
duuuuurrrrrrrrp
I copied my file into the same directory as the program and it worked fine.
Something embarrassing happened over the weekend while I was working on my program for reading files. When running the program through Code Blocks it would work great, but if I dropped to terminal and tried to run it I kept getting "file not found". I figured it was the terminal saying that it couldn't find my program and I spent about fifteen minutes fussing with permissions and checking to see what commands Code Blocks was doing that I wasn't when it finally dawned on me what was happening. "file not found" is the error message I wrote into the code for when it couldn't find my test file.
duuuuurrrrrrrrp
I copied my file into the same directory as the program and it worked fine.
Sunday, December 5, 2010
offsets
I think I'm going about this the wrong way, or rather perhaps there is a better way.
Should I load the entirety of the file into the appropriate data structures in one go and then have my "print to screen" parts tap into what is in them, or should I do it piecewise as needed where the function to print out one kind of data seeks to the location in the file where that data lives and then gets it?
EDIT:
Problem #1 right now is that the file I have been reading is really old and doesn't even have all the various data types - just spike waveforms. I'll have to remember to make a small file for myself at work tomorrow.
Should I load the entirety of the file into the appropriate data structures in one go and then have my "print to screen" parts tap into what is in them, or should I do it piecewise as needed where the function to print out one kind of data seeks to the location in the file where that data lives and then gets it?
EDIT:
Problem #1 right now is that the file I have been reading is really old and doesn't even have all the various data types - just spike waveforms. I'll have to remember to make a small file for myself at work tomorrow.
Dynamic allocation of multi-dimentional array
I've spent the late morning fleshing out my .plx file loader. It's mostly gruntwork right now making printf() lines for each interesting bit of info in the headers. At some point I'll get to the actual data itself, and I'm thinking of the best way to do this.
I know for a fact that there won't be more than 128 channels of information, and each channel will have various header data of its own. So, I could make a big array of size 128 of structures, or I could dynamically allocate the array based on the number of channels actually in the file.
Then, for each channel header it will have waveform data (32 points of digitized analog data) - again I won't know how many of these waveforms will exist until I read the channel header, so now I have an opportunity to dynamically allocate a multi-dimensional array of N x 32. I found this info:
http://c-faq.com/~scs/cclass/int/sx9b.html
which is clear enough on how to do it. It looks messy at first but it's probably the most straightforward way of doing it. I don't yet see how to access members of the array, but I'm one small test program away from figuring that out. I likely won't get to that part today.
I know for a fact that there won't be more than 128 channels of information, and each channel will have various header data of its own. So, I could make a big array of size 128 of structures, or I could dynamically allocate the array based on the number of channels actually in the file.
Then, for each channel header it will have waveform data (32 points of digitized analog data) - again I won't know how many of these waveforms will exist until I read the channel header, so now I have an opportunity to dynamically allocate a multi-dimensional array of N x 32. I found this info:
http://c-faq.com/~scs/cclass/int/sx9b.html
which is clear enough on how to do it. It looks messy at first but it's probably the most straightforward way of doing it. I don't yet see how to access members of the array, but I'm one small test program away from figuring that out. I likely won't get to that part today.
Subscribe to:
Posts (Atom)