integer to string converter(using macros) - c

I was doing basics of macros. I define a macro as follows:
#define INTTOSTR(int) #int
to convert integer to string.
Does this macro perfectly converts the integer to string? I mean are there some situations where this macro can fail?
Can I use this macro to replace standard library functions like itoa()?
for example:
int main()
{
int a=56;
char ch[]=INTTOSTR(56);
char ch1[10];
itoa(56,ch1,10);
printf("%s %s",ch,ch1);
return 0;
}
The above program works as expected.
Interestingly this macro can even convert float value to string.
for example:
INTTOSTR(53.5);
works nicely.
Till now I was using itoa function for converting int to string in all my projects. Can I replace itoa confidently in all projects. Because I know there is less overhead in using macro than function call.

Macros execute during (before to be exact) compile time, so you can convert a literal number in your sourcecode to a string but not a number stored in a variable
In your example, INTTOSTR(56) uses the stringification operator of the preprocessor which eventually results in "56". If you called it on a variable, you'd get the variable name but not its content.

In C, you can use itoa or if you are desperate and would like to avoid it, use snprintf for instance:
snprintf(my_str, sizeof(int), "%i", my_int);
The problem with your macro is that you are thinking about constants, but of course, your macro will be broken when you need to use a variable holding an integer. Your macro would try to stringify the macro name as opposed to the value it would be holding.
If you are fine with constants, your macro is "good", otherwise it is b0rked.

Your macro does not convert integers to strings, it converts a literal into a string literal, which is something very different.
Literals are any plain numbers or definitions of values in your code. when you do int x = 10; the numeral 10 in an integer literal, while x is a variable and int is the type. const char* ten = "10"; also defines a literal, in this case a string literal, with value "10" and a variable called ten which points to the address where this literal is defined. What your macro actually does is change the way the literal is represented before any actual compilation goes on, from an integer literal into a string literal.
So, the actual change is being done before any compilation, just at source code level. Macros are not functions and cannot inspect memory, and your convertion would not work with variables. If you try:
int x = 10;
const char* ten = INTTOSTR(x);
You would be very puzzled to find that your variable ten would actually hold the value "x". That's because x is treated as a literal, and not as a variable.
If you want to see what's going on, I recommend asking your compiler to stop at preprocessing, and see the output before your code is acutally compiled. You can do this in GCC if you pass the -E flag.
PS. Regarding the apparent "success" with conversion of float values, it just comes to show the danger of macros: they are not type-safe. It does not look at 53.5 as a float, but as a token represented by characters 5, 3, . and 5 in the source code.

Related

Wrong char output for Generic print C

I have a macro with _Generic for printing
#define PRINT(data) \
_Generic((data), \
char:print_char)(data)
and this is the implementation for print_char
void print_char(char data){
printf("%c\n",data);
}
The problem is that when I call PRINT('t') for example it prints 116 instead of t, the solution I found was to add (char) in PRINT statemen like PRINT((char)'t').
The question is how can I print the char without the cast?
For historical reasons, dating back to the early days when C lacked a type system and treated everything as int, a lot of things we would expect to be char are actually still int. There are many examples in the language:
character literals like 'A' are type int.
getchar returns an int.
EOF is an int.
ctype.h functions use int not char.
And so on. This is a well-known language defect. C++ changed several of these defects very early on, but C insists on remaining broken even to this day.
In C, plain character constants such as 't' have type int.
The PRINT macro could be changed to the following:
define PRINT(data) \
_Generic((data), \
int:print_char)(data)
If it is desired that PRINT should do something else for a "normal" integer value, then that would not be a suitable solution.

ASCI Escape Codes with #define value?

I have a #define'd value named HEIGHT with a value of 20.
I want to use the ASCI escape code "\033[HA" (where H is the number of lines the cursor is moved up.
However, when my code reads "\033[HEIGHTA", it is reading the 'H' as a different escape code (return cursor home). How can I include a #define'd value within an escape code?
Thanks
There are several alternatives, among them
Use a function instead of a macro to generate the escape code as needed. For example,
const char *cursor_up_seq() {
static char sequence[12];
if (sequence[0] == '\0') {
// one-time initialization
sprintf(sequence, "\033[%dA", HEIGHT);
}
return sequence;
}
As a variation on (1), do not produce the escape sequence as a standalone entity at all. Instead, embed it in whatever else you are printing, where it is natural to use (say) printf() to print the value of the HEIGHT macro.
But if you really want to produce a macro for a string literal containing the whole escape sequence, then you can do so by combining two C features:
the stringification (#) macro operator, and
automatic concatenation of adjacent string literals
Another answer, now deleted, attempted to demonstrate that, but floundered on one of the gotchas in that area. Here is a variation that works:
#define HEIGHT 20
#define STRINGIFY(x) #x
#define STRINGIFY_VALUE(x) STRINGIFY(x)
#define SEQUENCE "\033[" STRINGIFY_VALUE(HEIGHT) "A"
The resulting SEQUENCE macro expands to "\033[" "20" "A", which is 100% equivalent to "\033[20A" because of string literal concatenation. The gotcha here is that you cannot use STRINGIFY() directly for this purpose, because that does not macro-expand its argument before converting it to a string (per the standard behavior of #). Wrapping it in another macro layer (STRINGIFY_VALUE) results in that outer layer expanding the argument before presenting the result for stringification.

C define string as char

Is it possible to define a string as char in C like this? I think C calls it multi character constant.
#define OK '_/'
I want C to treat '_/' as a char from now on, not a string, so this:
printf("%c", OK);
prints _/ and not /
While it is technically valid C to define OK as '_/', the value of a multi-character character constant is implementation defined, so this is probably not something you want to do.
There is no way you will be able to print more than one character without resorting to strings.
Multi character constants are of int type and their value is not strictly defined-- it's platform dependent stuff. So using them as normal letters is not best idea, even though you can use them in every context as normal char there is no guarantee that they will be compiled as you intend (as in your example you get only last char from ur string).
here you have explanation of the topic:
Multiple characters in a character constant

format specifiers in scanf( ) in C?

Why do we pass the format specifiers to scanf( ) in C as its parameters?
I mean, can't we just do
scanf( &var ); // Here, var is any pre-declared variable.
the type of var can be fetched from its declaration. Why is this not allowed ?
I see the below code as a waste of memory.
scanf( "%d" , &var );
The type cannot be "fetched from it's declaration". There is nothing magical about scanf(), it's just a function. A function in C cannot access meta information about variables.
This is why, in general, function arguments are declared including their type. For variable-argument functions such as scanf(), the first argument is not optional and it is used to describe the number and type of the other arguments in some fashion chosen by the function itself.
You clearly need to read some book on C programming to get better understanding of the core concepts. Unlike some other languages, C doesn't have I/O mechanism baked into the language. scanf() is just a library function and as such, this function has no way to automagically know the type of the variable it is supposed to fill.
Because %d will simply specify what the type of var is, there is no memory wastage. scanf(&var) would not work because the function is not designed to accept arguments that way.
You know that variables in C can be of different types:
int: Integer
char: Character
float: Floating point number.
...
Unlike other languages, variable types cannot be implicitly inferred at compilation time in C. That is why you always declare the type of your variables ( Example: int a or char c).
Because scanf is just a function in C, and because functions in C should take parameters of a specific type, people who coded C decided to use the following format:
scanf("%d", &var) ; // for integers
scanf("%c", &var); //for chars
scanf("%f", &var); //for double and floats.
using %d or %c does not waste memory or whatsoever. you can think about it as a flag that specifies the type of the input variable.
Could the developers of C do it without %d, %c...etc? Yes they could, but then, they have to handle all possible exceptions that might arise from sending the wrong type.
Suppose the developers of C used just the following format
scanf(&var);
That is surly very concise, but then you will have to use the same syntax to send chars/int/double...etc, and then the function scanf has to figure out a way to decide about the type of the variable that was sent. Remember what I told you before? variable types CANNOT be implicitly inferred at compilation time, and thus, this task will be almost impossible.
They could however use a different scanf function for every type. For example:
scanfInt(&var); //for integers.
scanfFloat(&var); //for floats.
...
...
That would work perfectly, but it makes less sense to replicate the same code of scanf and use different functions just because the type is different.
So what is the solution? ==> Use the same function name ( scanf ), and then add a parameter (%d, %f, %c..) that will be used internally as a flag by C to know the parameter type.
I hope now you have a better understanding of the use of %d, %f....
There are two major points you are missing here.
First, we humans sitting at the keyboard will write something like:
char var = '0';
And we know that the "type" of this variable is char and we probably intend to store a character there. Once the compiler gets a hold of this it removes these "human" elements all that is left is at some memory location there is 1 byte reserved, further references to places in the code where we wrote "var" will interact with this memory location. That is all the compiler knows, there is no understanding of the intended variable "type".
Second, the format specificers do so much more than just indicate a simple type. Look at any page explaining scanf() and you'll see a long list, take special note of things like scan sets, negated scan sets, and expected input lengths.
Let's say I want the user to enter just a single digit, 0-9, well I don't have to just assume they will do as I ask, I can help ensure they will by using the format specifiers in scanf():
int var = 0;
print("enter 1 digit (0-9):\n");
scanf("%1d", &var);
Now, no matter how many digits they enter, I'll only have stored the first one.
What if you have a string that you want to read from the user, and you want to read everything up until you hit a new line character (read over spaces). We'll there are a number of options for this, but scanf can do it too. The "standard" to read a string is:
scanf("%s",some_string);
But that will stop at any whitespace character, so you wouldn't want scanf() to make an assumption in this case, you'd want to be able to use a specific negated scanset:
scanf("%[^\n]",some_string);

Implicit conversion in C?

What's going on here:
printf("result = %d\n", 1);
printf("result = %f\n", 1);
outputs:
result = 1
result = 0.000000
If I ensure the type of these variables before trying to print them, it works fine of course. Why is the second print statement not getting implicitly converted to 1.00000?
In the second case you have a mismatch between your format string and the argument type - the result is therefore undefined behavio(u)r.
The reason the 1 is not converted to 1.0 is that printf is “just” a C function with a variable number of arguments, and only the first (required) argument has a specified type (const char *). Therefore the compiler “cannot” know that it should be converting the “extra” argument—it gets passed before printf actually reads the format string and determines that it should get a floating point number.
Now, admittedly your format string is a compile-time constant and therefore the compiler could make a special case out of printf and warn you about incorrect arguments (and, as others have mentioned, some compilers do this, at least if you ask them to). But in the general case it cannot know the specific formats used by arbitrary vararg functions, and it's also possible to construct the format string in complex ways (e.g. at runtime).
To conclude, if you wish to pass a specific type as a “variable” argument, you need to cast it.
An undefined behavior. An int is being treated as float
The short answer is that printf isn't really C++. Printf is a C function which takes a variable argument list, and applies the provided arguments to the format string basis the types specified in the format string.
If you want any sort of actual type checking, you should use streams and strings - the actual C++ alternatives to good old C-style printf.
Interesting, presumably it's fine if your put '1.0'
I suppose the printf only gets the address of the variable, it has no way of knowing what it was. But I would have thought the compiler would have the decency to warn you.

Resources