How to store ASCII code of character in integer in C? - c

I am working on my C coursework and I need to get char as input and I want to store the ASCII value of that character in int variable. I know this can be done in the following way:
int main()
{
int x;
scanf("%c", &x);
printf("%d\n",x);
}
The problem here is that whenever I compile this program in gcc with -Wformat enabled, I get this warning:
Warning: format ‘%c’ expects argument of type ‘char *’, but argument 2 has type ‘int *’
According to the specifications of the coursework, I would loose some marks if there are any compiler warnings. So, is there any another way I can do the desired task without any compiler warnings?
In my actual program, I am scanning in an array and I would also need to store other integers which would be out of the range for char, so I cannot use char x

int main()
{
signed char x;
scanf("%c", &x);
printf("%d\n",x);
}
Correctly is to define x as char but int works as well.
Char is defined by the C standard to be a data type able to keep any ASCII character, i.e. at least 127 possible values. The sign does not matter, it is not specified.
If you need to use a char as an integer the best is to define it either with signed char or unsigned char, depending what you want to do.
On the other hand, printf("%d\n",x) will work correcrly because the type coercions will transform the input signed char to integer anyway, as printf%d expects.

Related

Warning while using strlen in C

I am new to C programming.I am trying to take input from a file line by line and print length of each line.
This is my code-
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char name[100];
printf("Enter file name\n");
scanf("%s",name);
FILE * input;
input=fopen(name,"r");
char line[100];
fscanf(input,"%s",line);
while(!feof(input))
{
printf("%d\n",strlen(line));
fscanf(input,"%s",line);
}
return 0;
}
This is my input file-
172.24.2.1
172.24.2.225
172.17.4.41
172.24.4.42
202.16.112.150
172.24.152.10
This is correctly printing the length of each line.But during compilation I get this warning-
In function ‘main’:
main.c:24:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘size_t’ [-Wformat=]
printf("%d\n",strlen(line));
So my question is why am I getting this warning although my output is correct and how can I fix this?
Thanks in advance.
The function strlen returns an object of type size_t (cf. ISO 9899:2011§7.24.6.3). You need to specify that the argument you pass to printf has type size_t, as opposed to int. You can do that by adding a z length modifier (cf. ISO 9899:2011§7.21.6.1/7) specifying an object of type size_t. You should also use the u formatting specifier as size_t is an unsigned type.
printf("%zu\n",strlen(line));

What is the need of hh and h format specifiers?

In the code below mac_str is char pointer and mac is a uint8_t array:
sscanf(mac_str,"%x:%x:%x:%x:%x:%x",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]);
When I try the above code it gives me a warning:
warning: format ‘%x’ expects argument of type ‘unsigned int *’, but argument 8 has type ‘uint8_t *’ [-Wformat]
but I saw in some code they specified
sscanf(str,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]);
which doesn't give any warning but both are working the same.
What's the need of using hhx instead of just x?
&mac[0] is a pointer to an unsigned char.1 %hhx means the corresponding arguments points to an unsigned char. Use square pegs for square holes: the conversion specifiers in the format string must match the argument types.
1 Actually, &mac[0] is a pointer to a uint8_t, and %hhx is still wrong for uint8_t. It “works” in many implementations because uint8_t is the same as unsigned char in many implementations. But the proper format is "%" SCNx8, as in:
#include <inttypes.h>
…
scanf(mac_str, "%" SCNx8 "… rest of format string", &mac[0], … rest of arguments);
hh is a length modifier that specifies the destination type of the argument. The default for conversion format specifier x is unsigned int*. With hh, it becomes unsigned char* or signed char*.
Refer to the table herein for more details.
hhx converts input to unsigned char, while x converts to unsigned int. And since uint8_t is typedef to unsigned char, hhx fixes warning.

gcc scanf warning believes float is double

I have a question regarding a warning message from the gcc compiler. The warning message occurs when an argument of scanf isn't a pointer to the variable that should carry the user input.
#include <stdio.h>
int main(int argc, const char *argv[]) {
float number;
scanf("%f", number); /* the value of 'number' is passed, instead of the adress to it */
return 0;
}
gcc will give the following warning message when it compiles the program.
scanf-problem.c: In function 'main':
scanf-problem.c:5:5: warning: format '%f' expects argument of type 'float *', but argument 2 has type 'double' [-Wformat=]
scanf("%f", number);
^
Like expected gcc wants the second argument of scanf to have the type 'float *' (the pointer to a float). What troubles me is that gcc believes that the second argument have the type 'double', when it actually have the type 'float'.
Which leads me to the question, why do gcc believe the second argument of scanf to be a double, when it actually is a float?
I have made some research on this topic to get an answer, but every answer I find is about how to get rid of the warning (write '&number' instead of 'number').
Which leads me to the question, why do gcc believe the second argument
of scanf to be a double, when it actually is a float?
Because float is promoted to double as specified in C Standard
6.5.2.2 Function calls
[#6] ... arguments
that have type float are promoted to double. These are
called the default argument promotions.
[#7] ... The ellipsis notation in a function prototype
declarator causes argument type conversion to stop after the
last declared parameter. The default argument promotions
are performed on trailing arguments.
You already know that you are passing wrong thing (as mentioned in comment) to scanf So just informing you reason behind the warning is float argument that you provide is first promoted to double.
Your compiler is right, the argument passed to scanf is indeed a double: for the ... part of the argument list a set of default conversions is performed. In particular all float arguments are promoted to double and this is what scanf gets to see.
[Edit] Other than posting the scanf() prototype, I now see the answer echoes #chill.
"imitation is the sincerest form of flattery."
Check the prototype for scanf()
int scanf(const char * restrict format, ...);
That ... means any number of any type of arguments are allowed. For historic reasons, all FP arguments of smaller than double are promoted to double when passed to such functions. That why the compiler calls it a double.
char, short are promoted to int too.
C11 6.5.2.2 6
" ... integer promotions are performed on each argument, and arguments that
have type float are promoted to double. These are called the default argument
promotions. ... "
The error message was misleading, scanf expect an address to the variable to fill the data back to it and you passed a value, and when scanf lookup that address it finds it to be different than what was suggested in formating "%f"
you can change it to
scanf("%f", &number); // &number instead of number
and it will work just fine

What do I do to stop an error "expected expression before ‘char’"?

I'm compiling my work and this error kept on appearing no matter how I edit my code:
expected expression before ‘char’
and
format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
as of the second error, I've tried to use typecasting but the problem is really persistent. Does anyone know how to?
This is a part of my code:
while ( char my_wget (char web_address[BUFLEN]) != EOF ) {
printf ("%s", (char) web_address[BUFLEN]);
Because you've got a syntax error where you wrote char and char is not allowed.
Maybe you had in mind:
int ch;
char web_address[BUFLEN];
while ((ch = my_wget(web_address)) != EOF)
printf("%s\n", web_address);
With the correct declaration for my_wget() around (such as extern int my_wget(char *buffer);), that should compile. You can't declare variables everywhere.
The second error is because web_address[BUFLEN] is a character (certainly in my code; it seems to be in yours, too, since the compiler managed to identify the type sufficiently to generate the error). It is also one beyond the end of the array if you declared it as I did. Treating a char value (probably an 8-bit quantity) as an address (pointer; probably a 32-bit or 64-bit quantity) is wrong, which is why the compiler complained.
In the printf() statement, try changing the part char to char*
Same applies to the condition in the while loop. Change the char before web_address to (char*)
I find it weird that you write "char" before my_wget(). Can you please be more specific?
See this code below
#include <stdio.h>
int main()
{
char c;
printf ("%s", st);
}
when i compile it , i get the same warning message.
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’
so i change the program to
#include <stdio.h>
int main()
{
char *str = "string";
printf ("%s", st);
}
And now the program compiles properly.
So being a newcomer to c , this is how you learn the language , write the smallest example , to prove that you have a firm grip over the concept.

type conversion in c

int main()
{
int x,y;
int z;
char s='a';
x=10;y=4;
z = x/y;
printf("%d\n",s); //97
printf("%f",z); //some odd sequence
return 0;
}
in the above piece of code the char s is automatically converted to int while printing due to the int type in control string, but in the second case the int to float conversion doesn't happen. Why so?
In both cases the second argument is promoted to int. This is how variadic functions work, and has nothing to do with the format string.
The format string is not even looked at by the compiler: it's just an argument to some function. Well, a really helpful compiler might know about printf() and might look at the format string, but only to warn you about mistakes you might have made. In fact, gcc does just that:
t.c:9: warning: format ‘%f’ expects type ‘double’, but argument 2 has type ‘int’
It is ultimately your responsibility to ensure that the variadic arguments match the format string. Since in the second printf() call they don't, the behaviour of the code is undefined.
Functions with variable number of arguments follow the rule of the default argument promotion. Integer promotion rules are applied on arguments of integer types and float arguments are converted to double.
printf("%d\n",s);
sis a char and is converted to int.
printf("%f",z);
z is already an int so no conversion is performed on z
Now the conversion specifier f expects a double but the type of the object after the default argument promotion is an int so it is undefined behavior.
Here is what C says on arguments of library functions with variable number of arguments
(C99, 7.4.1p1) "If an argument to a function has [...] a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined."
The char is not being promoted to int due to the control string. The char is working as an int because all data that is less than 4 bytes when passed to printf is bumped up to 4 bytes, which is the size of an int, because of the cdecl calling convention of variadic functions (the point of this is so that the data that comes next will be aligned on a 4-byte boundary on the stack).
printf is not type-safe and has no idea what data you really pass it; it blindly reads the control string and extracts a certain number of bytes from the stack based on what sequences it finds, and interprets that set of bytes as the datatype corresponding to the control sequence. It doesn't perform any conversions, and the reason you are getting some wierd printout is because the bits of an int are being interpreted as the bits of a float.
due to the int type in control string
That is incorrect. It is being converted because shorter int types are promoted to int by the var_args process. Int types are not converted to float types because the va/preprocessor doesn't know what formats are expected.

Resources