I'm curious if any of NI's efforts at enhancing memory management has provided the ability to determine if a file pointer (stream handle) is valid prior to using it?
fopen is of type FILE *, and if fclose is called on it, then it's no longer valid but it's not NULL either. I believe this is usually implemented as a malloc of a struct to hold the file info, so it's maybe the same issue as trying to determine if a malloc pointer is valid or not.
Is there any way to tell if a value of type FILE * is valid other than to try using it? It's a fatal error if it's bad and you use it in an fclose, fread, fwrite, etc. In std C, it's especially problematic since we can't catch the exception - you're guaranteed a program crash.
This may be an argument for using the WinAPI file functions Vs. the C std library file functions.
Thanks for any insight into this.
I do not know of any way to check to see if a pointer is valid, other than via some functions like IsBadReadPtr, which microsoft even strongly recommends against using, or via Structured Exception Handling. My understanding is that, in general, trying to catch invalid pointers is a very bad idea. The MSDN blog has a very candid discussion of functions like IsBadReadPtr here: http://blogs.msdn.com/b/oldnewthing/archive/2006/09/27/773741.aspx
It wouldn't be necessary except for the fact that NI's C std lib implementation is to incur a fatal error on any operation on an invalid stream (well, except for fopen).
So the question really is, "How can I tell if a stream is valid before I use it" ? That a C std lib stream is apparently implemented as a pointer instead of a handle is why it's a problem.
If it were a handle, then I could check for an invalid handle value.
I could convert everything to use NI's file I/O library, but that's a pain because of function names being the same as Win32 functions (and please don't tell me about the macro I can use) or I could use WinAPI file i/o calls but that's even more work.
C doesn't support structured exception handling.
If I understand your problem correctly, you're already using NI's file I/O library, aren't you? These streams are created by fopen, and disposed (i.e. made invalid) by fclose, right? So, if your problem is trying to find out whether a stream that you're using in some part of your program had already been closed by a different part of your program, couldn't you simply set the stream pointer to NULL right after you close it?
Actually, it would have been nice if fclose set the stream to NULL on its own, but I do set it to NULL after an fclose, and I check for the stream being NULL prior to every use.
My problem was with a multi-threaded app that could catch the file closed but the stream not yet NULL.
So I had to use a lock to coordinate access between the threads to prevent this.
fopen, fclose, fwrite etc are part of the C std library (as implemented by NI), as opposed to the OpenFile, CloseFile, WriteFile calls which use handles, as do the WinAPI file i/o calls. The handle abstraction allows the implementation to avoid using a raw pointer that can be improperly dereferenced and cause an exception that a CVI C app can't catch.
It might be that the C89 / C99 std requires the std lib implementation to use a pointer for the stream, as the language calls it a "stream" but it's type is actually FILE *.
So I'm complaining about C std lib more so than the CVI std lib implementation I suppose.
After all, NI came up with its own CVI file I/O package separate from the C std lib file i/o, and NI did use handles for this other library. If you misuse a handle, you don't get a fatal error, you get a return status indicating an error. The issue is that the C std lib calls are standard (i.e. portable), and fairly easy to understand and use, so it'd be nice to use them.
Yes, your suspicions are correct. CVI cannot deviate one iota in its C stdlib from what the ANSI C89/C99 spec mandates. I would have also recommended that you create a mutex lock around critical changes to your file stream. The library calls themselves are already locked, but any code that you add to "tag" the stream with a NULL would also have to be inside the mutex.
The Format I/O library that you're referring was created back before CVI was ANSI-compliant. (It wasn't even called "CVI" back then). It predates the ANSI C library. You could use this library instead, but then you lose code portability.