I made a short code like below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int32_t main(int32_t argc, int8_t *argv[])
{
int32_t i;
if (argc < 1)
{
printf("Error\n");
}
for (i = 0 ; i < argc ; i )
{
printf("argv[%d] = %s\n", i, argv[i]);
}
return 0;
}
And compiled like below, then I see a warning like below.
$ gcc -W -Wall main.c
main.c:6:9: warning: second argument of ‘main’ should be ‘char **’ [-Wmain]
int32_t main(int32_t argc, int8_t *argv[])
What is the best practice to use int8_t?
CodePudding user response:
At its root I believe you're asking a style question, which means you're unlikely to get a definitive answer. Opinions on style are, well, opinions.
Some people believe that you should use C's "natural" types — char, short, int, long, and their unsigned variants — most of the time, and that you should use exact-size types like int32_t only when you absolutely have to.
Some people believe that the variability implied by the "natural" types is an unrelenting source of bugs, and they believe that you should use exact-size types always.
Now, with that said, the specific case of writing
int32_t main(int32_t argc, int8_t *argv[])
is objectively wrong, for at least three reasons:
- On a platform where type
intis 16 bits, this wrongly declaresmain's return type, and the type of theargcargument, as a 32-bit type. - On a platform where type
charis unsigned, this wrongly declaresargvas an array of signed character pointers. That's probably what gcc was complaining about for you. - On a more philosophical level,
mainis not a function whose function signature you get to pick. Somebody else declaredmain, somebody else is callingmain, your job is only to provide a definition formain. So you simply have to use the types somebody else specified, even if your rule is that you want to use exact-size types whenever you can. Here, you can't.
Bottom line: Please use one of these two (equivalent) forms for main with arguments:
int main(int argc, char *argv[])
int main(int argc, char **argv)
Unless you're writing "freestanding" code, anything else is confusing, misleading, nonstandard, or wrong. (It's also acceptable to define a main that takes no arguments.)
What is the best practice to use int8_t?
I would say, when you really, really need a tiny, 8-bit, signed integer, or perhaps when you're manipulating memory as signed bytes. But I would not go using int8_t instead of char everywhere, because it's going to cause you lots of problems, and it's not going to buy you anything.
CodePudding user response:
What you have posted is an implementation-defined form of main(). It is only allowed in two cases:
- Either it is 100% compatible with
int main (int argc, char** argv), or - It is an implementation-defined form that the compiler documentation have told you is fine to use.
It is the C standard and the compiler which decide the acceptable forms of main(), never the programmer.
Notably int8_t may or may not be compatible with char, since char has implementation-defined signedness.
CodePudding user response:
What is the best practice to use int8_t?
When you need a very small signed integer. That's not the same as char. char comes in three flavours:
signed char
unsigned char
char
If you know you want a signed int8_t, use it. If you are dealing with standard string API:s, like main, use char.
int8_t doesn't even need to exist. It's implementation specific. There are platforms where it doesn't exist.
The same goes for int32_t that you use instead of int. It doesn't necessarily exist and even if it does, it's not always a typedef for int - so use int if you want to stay portable.
CodePudding user response:
Your approach has many drawbacks:
the prototype for
main()is not compatible with any of the standard ones, even ifinthas 32 bits and ifcharis signed becausecharandsigned charare different yet compatible types butchar *andsigned char *are incompatible types.if
intis not the same asint32_t, the prototype is definitely incompatible with the standard one and the behavior is undefined.printf("argv[%d] = %s\n", i, argv[i]);would have undefined behavior if typeintis not exactly the same asint. You could use the macros from<inttypes.h>, but they are rather cumbersome and would be the code less readable.
Hence the prototype for your main function should be int main(int argc, char *argv[]) and for consistency, i should be defined with the same type as argc: int.
The resulting code is quite simple and readable:
#include <stdio.h>
int main(int argc, char *argv[]) {
int i;
if (argc < 1) {
printf("Error\n");
}
for (i = 0; i < argc; i ) {
printf("argv[%d] = %s\n", i, argv[i]);
}
return 0;
}
I would argue that best practice regarding int8_t vs char is to use standard prototypes unchanged for main and all library functions. It is also advisable to use char for actual characters used for text as opposed to int8_t and uint8_t for signed and unsigned bytes read from binary contents. String literals should be considered const and manipulated via const char *. Code should behave in a defined manner regardless of the signedness of the char type. This is not just a question of style, it is a sane habit to improve code readability and sturdiness, avoid confusion and some mistakes.
