Convert a char with va_arg - c

I need to get from va_arg a char.
i use an integer, but my problem it's does not work !
char c = (char)va_arg(ap, int);
write(1, &c, 1);
it's gave the ascii code of something else.

Arguments to variadic functions (the ones corresponding to the ... in the declaration) undergo the default argument promotions.
Integer arguments narrower than int are promoted to int (or to unsigned int if the type is unsigned and its maximum value exceeds INT_MAX), and arguments of type float are promoted to double.
So you can't get a char from va_arg(). The obvious
char c = va_arg(ap, char); // DON'T DO THIS
has undefined behavior.
What you're doing:
char c = (char)va_arg(ap, int);
looks correct, though the (char) cast is unnecessary; the int result will be implicitly converted to char anyway.
For example,this program's output is c = 'x':
#include <stdio.h>
#include <stdarg.h>
void func(int first, ...) {
va_list ap;
va_start(ap, first);
char c = va_arg(ap, int);
va_end(ap);
printf("c = '%c'\n", c);
}
int main(void) {
func(42, 'x');
}
You need to update your question to describe what the actual problem is. You say "it's gave the ascii code of something else"; I have no idea what that means.

Related

About conversion specifier of scanf in C

I have a question about conversion specifier of scanf in C.
#include <stdio.h>
int main(void)
{
int num1;
scanf("%hhd",&num1);
printf("%d \n",num1);
}
Since I have typed "%hhd" as the conversion specifier in scanf function, when my input is "128", I expect -128 to be stored in num1. But the result shows that 128 is stored in num1.
Why does this happen even though I have used "%hhd" to specify input as char int?
Step 1 With scanf() issues: check results. Unless the return value indicates something was written into num1, printing it does not reflect user input.
int num1;
if (scanf("%hhd",&num1) == 1) {
printf("%d \n",num1);
}
Step 2: Enable compiler warnings. Saves time.
if (scanf("%hhd",&num1) == 1) {
// warning: format '%hhd' expects argument of type 'signed char *',
// but argument 2 has type 'int *' [-Wformat=]
Why does this happen even though I have used "%hhd" to specify input as char int?
This in not about integer types: int versus char. The is about pointers: int * versus signed char *. "%hhd" in scanf() matches a pointer: signed char * (or unsigned char * or char *), not an int nor char.
Code passed &num1, a int *. Compliant code would pass a signed char *.
If a conversion specification is invalid, the behavior is undefined. C11 §7.21.6.2 13
That is it. Code broke the rules, expected behavior does not occur. Use the correct type.
signed char num1;
if (scanf("%hhd",&num1) == 1) {
printf("%d \n",num1);
}
If code must save the result in an int:
int num1;
signed char ch1;
if (scanf("%hhd",&ch1) == 1) {
num1 = ch1;
printf("%d \n",num1);
}

passing argument makes pointer from integer without a cast

I've read through several similar questions on Stack Overflow, but I've not been able to find one that helps me understand this warning in this case. I'm in my first week of trying to learn C though, so apologies if I've missed an obvious answer elsewhere on Stack Overflow through lack of understanding.
I get the following warning and note:
warning: passing argument 2 of ‘CheckIfIn’ makes pointer from integer without a cast [enabled by default]
if(CheckIfIn(letter, *Vowels) ){
^
note: expected ‘char *’ but argument is of type ‘char’
int CheckIfIn(char ch, char *checkstring) {
When trying to compile this code:
#include <stdio.h>
#include <string.h>
#define CharSize 1 // in case running on other systems
int CheckIfIn(char ch, char *checkstring) {
int string_len = sizeof(*checkstring) / CharSize;
int a = 0;
for(a = 0; a < string_len && checkstring[a] != '\0'; a++ ){
if (ch == checkstring[a]) {
return 1;
}
}
return 0;
}
// test function
int main(int argc, char *argv[]){
char letter = 'a';
char *Vowels = "aeiou";
if(CheckIfIn(letter, *Vowels) ){
printf("this is a vowel.\n");
}
return 0;
}
Vowels is a char*, *Vowels is just a char, 'a'. chars get automatically promoted to integers, which your compiler is allowing to be implicitly converted to a pointer. However the pointer value will not be Vowels, it will be the address equal to the integer encoding of the character 'a', 0x61 almost universally.
Just pass Vowels to your function.
In your case, the type conversion is from char to integer pointer. In some cases, the function takes void pointer as the second argument to accommodate for all the data-types.
In such cases, you would need to typecast the second argument as (void *)
This would be the function declaration in most well written modular functions:
int CheckIfIn(char ch, void *checkstring);
You would need to pass the argument as a void pointer, provided the Vowels is not a char pointer
if(CheckIfIn(letter, (void *)Vowels) ){
printf("this is a vowel.\n");
}

I have got a decode error when I try to print a string got from va_list of C

It runs well, but if I delete the third line in main() "printf("(main)s: %s\n",s);
The output encounters a decode error: it print unrecognized chars instead of helo world.
Here is my code :
#include <stdio.h>
#include <stdarg.h>
void fun1(int i, ...){
va_list arg_ptr;
char *s=NULL;
va_start(arg_ptr, i);
s=va_arg(arg_ptr, char*);
va_end(arg_ptr);
printf("address of s in fun1: %x\n",&(*s));
printf("(fun1)s: %s\n",s);
return;
}
void main(){
char *s = "hello world";
printf(" address of s: %x\n",&s);
printf("(main)s: %s\n",s);
fun1(4);
}
How can i fix this ?
Seems you love UB.
%x is not for printing pointers. Use %p (but only for printing void* or char*).
You are taking the first var_arg_parameter, but you didn't pass one.
Unless you are in a freestanding environment (microcontroller or such), you have a bad prototype for main. Use int main() or int main(int argc, char** argv).
In addition, you probably want to print s resp. the param you passed, not where it's stored.
Added for clarification: UB means Undefined Behavior, an acronym any C / C++ programmer should know by heart. It literally means, "This program can exhibit any behavior whatsoever, including making demons fly out of your nose." What actually happens in any specific instance can be completely unpredictable and change at the drop of a hat.
#include <stdio.h>
#include <stdarg.h>
void fun1(int i, ...){
va_list arg_ptr;
char *s; /* removed superfluous initialisation */
va_start(arg_ptr, i);
s=va_arg(arg_ptr, char*);
va_end(arg_ptr);
printf("address of s in fun1: %p\n",(void*)&s);
printf("value of s in fun1: %p\n",s);
printf("address of string s: %p\n",s);
printf("value of string s: %s\n",s);
return;
}
int main(){
char *s = "hello world";
printf("address of s in main: %p\n",(void*)&s);
printf("value of s in main: %p\n",s);
printf("address of string s: %p\n",s);
printf("value of string s: %s\n",s);
fun1(4, s); /* fun1 will always access the first var-arg parameter as a string, so you must provide it */
return 0; /* can be omitted but only for main, so why do it? */
}
Because you printf function says %x and not %s The %x is for unsigned hexadecimal integer and the %s is for a string of characters.
warning: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'char**'
To print the address of your char array you could try copying the value of the array to an int variable.
Your problem is
printf(" address of s: %x\n",&s); ///< this line right here
The variable s is a char*, and &s is a char**, using %x you are implicitly casting your char** to int and will be printed in hex.
(ISO/IEC ISO/IEC 9899:1999 (E), §6.3.1.1) [...] If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.
I heard that you only have a problem when you remove the line: printf("(main)s: %s\n",s);.
So if your char** gets implicitly converted to int or uint and then gets presented in hex who knows what address are you looking at.
You can check everything about how to format printf here

Standard C cast of va_arg return value warning

I am developing a C program and have been stumped by this warning. I want to retrieve arguments from the list using va_arg.
args[i] = (int) va_arg(argptr, int);
or
args[i] = (char) va_arg(argptr, char);
the problem that am getting this warning:
... void *' differs in levels of indirection from 'int'...
the same also for char case.
Any explanation for that?
code:
void test_function(va_list argptr, int (*callback)(),
int ret_typel)
{
int i ;
int arg_typel;
int no_moreb = TRUE;
void *args[MAX_FUNCTION_ARGS];
for (i=0; no_moreb; i++) {
arg_typel = (int)va_arg(argptr, int);
switch(arg_typel) {
case F_INT:
args[i] = (int) va_arg(argptr, int);
break;
case F_CHAR:
args[i] = (char) va_arg(argptr, char);
break;
default:
no_moreb = FALSE;
i--;
break;
}
}
}
A point of detail about the use of va_arg().
You cannot use:
va_arg(argptr, char);
without invoking undefined behaviour (which is bad!). The variable arguments to a varargs function undergo promotions: float is passed as double, and char, unsigned char, signed char, short, unsigned short undergo promotion to int or unsigned (int) as required. Therefore, you can never pull a char directly with va_arg; you can only specify promoted types. You would have to write:
char c = (char) va_arg(argptr, int);
float f = (float) va_arg(argptr, double);
This time, the cast occurs as a result of the assignment; saying it happens with the cast is not strictly necessary, but does no harm (though I probably wouldn't write the cast in my own code).
The problem is that args[] is an array of void *. You cannot assign an int or float to a void * (it doesn't make any sense). You could get round this by casting, but it's not a good idea.
If you want to store different types in the same variable, consider a union:
typedef union
{
char c;
int i;
float f;
} MyUnion;
MyUnion args[MAX_FUNCTION_ARGS];
args[i].c = va_arg(argptr, char);
args[i].i = va_arg(argptr, int);
args[i].f = va_arg(argptr, float);
UPDATE
As Jonathan Leffler correctly points out in his answer, va_arg(argptr, char) and va_arg(argptr, float) should not be used, due to default promotions for variadic functions.
The array args is a array of void *. You assign plain integers to it, which is the reason you get the error.
You're being passed a void pointer and you are casting the pointer as an int or char. You need to dereference the void pointer and then cast, or cast it as an (int *) or (char *) first.

'stripspaces' makes integer from pointer without cast

#include <stdio.h>
#include <ctype.h>
#define STRING_LEN 500
void stripspaces(char, char, char);
int main(void)
{
char string[STRING_LEN];
char *p1 = string;
char *p2 = string;
printf("Enter a string of up to %d characters:\n", STRING_LEN);
while((*p1++ = getchar()) != '\n') ;
stripspaces(string, *p1, *p2);
getch();
return 0;
}
void stripspaces (char s, char *x1, char *x2){
*x1 = '\0';
x1 = s;
while(*x1 != '\0')
{
if(ispunct(*x1) || isspace(*x1))
{
++x1;
continue;
}
else
*x2++ = *x1++;
}
*x2 = '\0';
printf("\nWith the spaces removed, the string is now:\n%s\n", s);
}
This code is bringing up the following error at the 'stripspaces' function; "passing arg 1 of 'stripspaces' makes integer from pointer without a cast" any help would be excellent.
In case it is not obvious from the code, the program should take in a string and remove all the spaces from it. The function has to remain although I know I can do it without the function.
Your prototype and function definition don't match:
void stripspaces(char, char, char);
vs.
void stripspaces (char s, char *x1, char *x2)
You should change the prototype to
void stripspaces(char, char*, char*);
And in order to make them both work, you should use
void stripspaces(char*, char*, char*);
and
void stripspaces (char *s, char *x1, char *x2)
.
For easier copy & paste, you can use parameter names in the prototype as well.
Both of the answers above are telling you that your function declaration is wrong. Also you are dereferencing pointers when passing them to the function.
stripspaces(string, *p1, *p2);
This turns the call into (char*, char, char) which is not right and will not behave as you expect it to. It is also the source of the particular compiler error you are seeing. The compiler is trying to fit the string(char*) into a char, and thus making an "integer from pointer without cast" since char is basically an 1 byte integer.
Correcting the function declaration would be step one, you want to pass all pointers or you won't be able to manipulate the string.
Fix the declaration and then call the function like this.
stripspaces(string, p1, p2);
You need to change the first argument from char s (single character) to char *s (pointer)

Resources