0

I wrote the following code to convert int value to char pointer and this works in C.

int i = 54;
char *ii;
ii = &i;
printf("%d\n", *ii);

The output is:

54

While when I write the same in C++, it doesn't work.

int i = 54;
char *ii;
ii =  (char *)&i;
cout<<*ii;

The output is:

6

Can someone please explain why this happens and how shall I get it working in C++.

Thanks in advance.

Shubham Yadav
  • 561
  • 7
  • 16
  • 3
    Looking through an [ASCII table](https://en.cppreference.com/w/c/language/ascii) could be very helpful. – Some programmer dude Jan 05 '19 at 14:08
  • No, it's a bit different. In the question https://stackoverflow.com/questions/17813423/cout-with-char-argument-prints-string-not-pointer-value the user isn't able to print the address of the pointer, whereas I am not getting the correct value that the int holds. its quite different – Shubham Yadav Jan 05 '19 at 14:09
  • 1
    The duplicate is not a perfect duplicate, but the basic problem and solution is the same: Printing a `char` in C++ prints a `char`, i.e. the character the encoded value represents. – Some programmer dude Jan 05 '19 at 14:11
  • 1
    Also note that you dodged *one* bullet by not having a [big-endian](https://en.wikipedia.org/wiki/Endianness#Big-endian) system. – Some programmer dude Jan 05 '19 at 14:12
  • 2
    @ShubhamYadav - you're just getting lucky (or unlucky, depending on viewpoint). Evaluating `*ii` (in order to print it) gives undefined behaviour, in both C and C++ samples. There is no requirement that the value printed by what you assigned. The only difference is that a C++ compiler has to be forced to allow the initialisation of a`ii` (i.e. using an explicit type conversion), but a C compiler does not. The net result is that there is no guarantee about what value your code prints, in either language. – Peter Jan 05 '19 at 14:13
  • 2
    This is not a duplicate of that question. The behaviour in the first part is like: `reinterpret_cast(*reinterpret_cast(&i))` (Which is legal, as `char*` is the object representation, and if it explicitly casted would be required to print `54`), and the second is just `*reinterpret_cast(&i)` (Which in this case the first byte is `(char) 54`, which as ASCII is `'6'`. On platforms with the opposite endianness, it would have printed the nul byte `'\x00'`) – Artyer Jan 05 '19 at 14:50
  • 1
    @Peter A `char *` is allowed to alias other types for the purpose of accessing the representation of the pointed-to object. The result is implementation defined, not undefined. – dbush Jan 05 '19 at 15:41
  • You are trying to trick the compiler. Ask it to do something you want the right way, and you'll get the result you want/expect. – Déjà vu Jan 05 '19 at 15:46

2 Answers2

2

When you call printf like this:

printf("%d\n", *ii);

The %d format specifier means that the given int argument will be printed as an int. Even though what you pass is a char, because printf is a variadic function it is promoted to an int, so it matches the format specifier.

When you output using cout:

cout<<*ii;

The << operator has an overload for a char. Since the right side has type char, that's the overload that is used. That particular instance of << prints the argument as a char. Since the ASCII code 54 corresponds to the character '6', that's what gets printed.

You'll get the opposite results if you use %c in the printf format, and if you cast *ii to int in the cout call.

dbush
  • 205,898
  • 23
  • 218
  • 273
1

Different isn't the same. Try this:

#include <cstdio>
#include <iostream>

int main() {
    int i = '6';
    char *ii = reinterpret_cast<char*>(&i);
    std::printf("%c\n", *ii);
    std::printf("%d\n", *ii);
    std::cout << *ii << '\n';
    std::cout << (int)*ii << '\n';
}

Initializing i to '6' is just a clarification.

In the calls to printf, the char value that *ii points to is promoted to int in the function call. Types smaller than int get promoted when they're arguments to the variable part of a function that takes a variable parameter list (such as printf).

The first printf statement prints the value of *ii as a character value; you'll get "6". The second prints it as an integer value; you'll get whatever value represents the character '6' (in ASCII that's 54, which is probably what you'll see).

The first insertion into std::cout inserts the char value; stream inserters are overloaded for integral types, so you get the inserter that takes an argument of type char, and it displays the character that the value represents, just like the first printf call.

The second insertion into std::cout inserts the integer value of *ii, just like the second call to printf.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165