Zepper wrote:
News to me. I didn't know about such thing, example:
FILE fp = fopen(path, mode);
without the * (pointer).
No, you don't do that unless the documentation for
fopen() on your platform tells you it returns a struct on the stack rather than a pointer (I've never seen any which do). You comply with what the documentation tells you. Example:
fopen() on FreeBSD. Thus this is the code you'd want:
Code:
FILE *fp;
fp = fopen(path, mode);
And NOT:
Code:
FILE fp;
fp = fopen(path, mode);
The latter will throw a warning about "incorrect assignment" or something along those lines, and will absolutely be unreliable/break/crash/whatever because
fopen() returns a pointer, not the entire contents on the stack of whatever
FILE is. Different levels of compiler optimisation may actually result in code that works despite the warning (that's based on my own experience). Here's proof of the warning:
Code:
1 #include <stdio.h>
2 int main(int argc, char *argv[]) {
3 FILE *fp1;
4 FILE fp2;
5
6 fp1 = fopen("dicks", "r");
7 fp2 = fopen("dicks", "r");
8
9 return 0;
10 }
Code:
$ gcc -Wall -o x x.c
x.c: In function 'main':
x.c:7: error: incompatible types in assignment
As for zlib and it's gzip-related functions, it seems quite clear to me what you want is to declare your
gzFile variable as
gzFile myvarname. Look at
the declaration for gzopen and what it returns.
Now, all of the above is talking about functions and what they return to you on the stack -- passing an argument to a function, and what you pass, based on what it's declared as, also matters. For example, take the following pieces of code (let's stick with
fopen() shall we?). These two are the same:
Code:
FILE fp;
fp = fopen("/some/file.gz", "r");
Code:
char *path = "/some/file.gz";
FILE fp;
fp = fopen(path, "r");
These two are the same. They both statically allocate space within one of the segments (
.text or
.data or something, I forget) within the program loaded at run-time for the path/filename itself. The difference is that in the latter case, there's now a variable called
path that points to this preallocated string. You can also manipulate
path within the 2nd program if you wish, i.e.
path[1] = 'h' which would turn the path into
/home/file.gz; if you declared it as
const char *path you wouldn't be able to do this (you'd get an error about trying to modify a read-only variable or something to that effect).
This becomes more complex when something that is typedef'd is a struct -- and
this appears to be the case with zlib's
gzFile. In fact, there was an example of that exact situation
in this thread, specifically these posts where the author forced a cast on something when he shouldn't have, and -- more importantly -- was passing the wrong thing to
memcpy() (which happily stomped all over the memory regions allocated for his program). I provided a write-up explaining when it's proper to hand a function the address of the variable itself (using
&var) rather than just
var:
*
viewtopic.php?p=104677#p104677*
viewtopic.php?p=104680#p104680*
viewtopic.php?p=104703#p104703*
viewtopic.php?p=104705#p104705*
viewtopic.php?p=104706#p104706So, the bottom line: if a compiler throws a warning at you, pay attention to it.
DO NOT just start typecasting things to clean up warnings, or start force dereferencing (i.e.
function(*myvar)) -- more often than not a forced cast still means your code is buggy/wrong and no longer does the compiler tell you about it, and forced dereferencing is only necessary when you
know it's needed (and understand what this does). Instead ask for help or advice; sometimes casting is the correct solution, but most of the time I see people force casting for no good reason or because they're trying to get rid of warnings that indicate an actual problem. I only rarely see people dereferencing manually, and it's usually done within complex string manipulation or string parsing functions (where manipulating the address of a pointer, to point to parts of a string, are used heavily).