Introduction to the problem
So a few months back while i was really struggling to get better at C, i decided maybe its time for me to ditch the usual var types, char, short, int, long in favor of the alias provided in stdint.h those being the uint8_t, etc... The initial problem is that declaring long on some machine's has different byte size lengths than others but soon i started to see that it became a snob thing for me to "differentiate" me from other IT student's.
I'm now doing a project and as always, I started to use the variables aliases mentioned above, as they are easy for me to read, write and i don't have to wonder what storage allocation will my computer choose to use(i know the size doesn't change at will and its dependent on the computer running it, but not being evident and explicit causes me to just obsess over it).
As usual my debugger start's complaining from time to time especially due to pointer conversion's like so
Passing 'int8_t *' (aka 'signed char *') to parameter of type 'char *' converts between pointers to integer types where one is of the unique plain 'char' type and the other is notclang(-Wpointer-sign)
The Question
Although i usually just explicitly cast them i am just wondering if I'm making the code worse because of a preference of mine, and what is the good practice: using a more universal(to the project) variable alias, or just using the aliases depending on how will they be used(this implies using 2-3 different aliases on a file and probably 10 project wide)?
Example
png_voidp per_chunck_ptr;
size_t readnum;
FILE *fp;
if ((fp = fopen(file, "rb")) == NULL){
fp = NULL;
//ERROR()
//ABORT(GENERAL_OPENING_READ_FILE_ERROR, " ERR01 ");
}
int8_t *pop;
pop=malloc(GENERAL_PNG_SIG_SIZE * sizeof(int8_t));
readnum=fread(pop,sizeof(int8_t),GENERAL_PNG_SIG_SIZE,fp);
if(readnum!=GENERAL_PNG_SIG_SIZE){
fclose(fp);
//ERR 5
fp = NULL;
fprintf(stderr, GENERAL_READ_FILE_ERROR, "ERR02");
exit(5);
}
if(png_sig_cmp((png_const_bytep)pop, 0, GENERAL_PNG_SIG_SIZE)!= 0){
fclose(fp);
fp = NULL;
fprintf(stderr, "File is not recognized as png file\n");
//err 6
exit(6);
}
free(pop);
The error checking is terrible, i use like 6-7 different ways to print error's for no other reason than me learning new functions or just getting distracted and using a certain one once and forgetting it there but although the answer could extend to it lets only focus on the variable pop for now
At the time i was pretty sure that the pointer "pop" would be used in the future as a parameter of a function which typically prefers png_bytep or in this case png_const_bytep and furthermore i the library has their own function for allocating memory although from what I've seen its not much different in its manner than using malloc, (although i haven't read the manual for the specific implementation and only know a few generic theoretical concepts about the designation(if you haven't figured it out, its PNG).
Now lets focus on size_t readnum, this part goes against what i said earlier since im using another alias when i could've just said uint64_t, the thing is that if im not wrong size_t can store the maximum size of a theoretically possible object of any type (including array).
(although there's types for bigger "words", like long double, which for what I've read is 10 bytes long, or __uint128_t which 16 bytes these aren't as easily used by the cpu and they require optimizations on software to be able to store and manipulate them, and again correct me here if im wrong) so i shouldn't use a uint8_t here because i know that if someday cpu manufacturers decide to increase the bit size, of the register storage, ALU, and memory adresses(i heard my professor even say that modern intel ones sometimes had around 80 bits) to something like 128 bits the size_t would move and my function could fail if it ever overflowed. This caused me to not use uint64_t
Conclusion
So should i just quit using my preferences of exact variable size and instead use the variable aliases that the functions use, or is using exact size alias really better as they allow to define certain behavior more precisely
CodePudding user response:
As a general rule, use the exact width types when you need to control exactly how big a particular variable is, using any kind of bit manipulation, or when dealing with raw data. You would use the base types when interacting with an API that specifies those types, i.e. if a function expects a long
, pass it a long
instead of a uint64_t
.
Regarding the specific warning you're getting, that's because the type char
may be either signed or unsigned, depending on the implementation. So if you were to pass a int8_t *
to a function expecting a char *
, and that system happens define char
as an unsigned type, then you have a mismatch.
This isn't a big deal however, since it's allowed to access an integer object via a pointer to either the signed or unsigned version of its type.
CodePudding user response:
First of all, why are you trying to cast an int8_t *
into a char *
(aka uint8_t *
)? The warning is for your code's safety. It's not because you're using aliases but because you're implicitly casting a signed integer type into an unsigned one.
In practice, you should use whatever your API expects. And, if you're not using any other library or stuff like that, use whatever suits you the best. If you want to be specific about the size, use the stdint.h
values and if you want to be vague about the sizes(for eg. you want to second biggest type) use the normal C keywords. Beware that the "second biggest" type may be the same as the biggest or the third biggest.