7

How do i properly identify a type of variable in c++. I tried this to identify a type of variable :

int a = 5;
std::cout << typeid(a).name() << std::endl;

And instead of the expected output int, it gives you:

i

I Am Very confused on why that is happening.. Its somehow giving you only the first letter of the type you are declaring the variable. Int is not the only one... also this:

 char a = 'A'
 std::cout << typeid(a).name() << std::endl;

Example Program

Is there a simple workaround to this? Any Help would be appreciated!

Ultron
  • 21
  • 4
amanuel2
  • 4,508
  • 4
  • 36
  • 67
  • 1
    You seem to be confusing "identification" and "producing C++ source code"...? Identification just means you can assign some unique characteristic to something that you can later use for lookup and comparison. There isn't any facility in C++ in general that can create a source-level string representation of some language construct. – Kerrek SB Apr 29 '16 at 22:42

3 Answers3

13

There are two problems with your code,

Firstly typeid(..).name() returns an implementation defined string, it can be any valid string, it could return "" for every type, it could even return different values for each program execution (though I believe the value can't change during execution). GCC (and Clang?) return unreadable names, whereas Visual C++ returns reasonable ones (in this case int)

Secondly if the type of a is a polymorphic type, typeid(a) will return the typeid corresponding to the dynamic type of a and not the type that was used to declare a, instead use typeid(decltype(a)).

Unfortunately there is no standard way of getting the name of a type in a way that is human readable or correct C++ syntax. (see Unmangling the result of std::type_info::name if you want a way that works in GCC)

EDIT Using Boost, you could try std::cout << boost::typeindex::type_id<decltype(a)>().pretty_name() << std::endl;, see Getting human readable and mangled type names

Community
  • 1
  • 1
Isaac
  • 816
  • 5
  • 12
  • 3
    `typeid` on a non-polymorphic type is fine - it just gives you info on the static type, without evaluating the expression. See e.g. http://en.cppreference.com/w/cpp/language/typeid. – Alan Stokes Apr 29 '16 at 22:50
  • So you cant get the type of a variable in c++?? – amanuel2 Apr 29 '16 at 22:59
  • @Dsafds you can, `decltype(a)` gets the type, you can get a ‘name’ for the type with `decltype(typeid(a)).name()` but there's no portable way of getting any meaningful/understandable name, sorry . – Isaac Apr 29 '16 at 23:03
  • When i do that @Isaac it gives me error: main.cpp: In function 'int main()': main.cpp:10:22: error: expected unqualified-id before 'decltype' std::cout << std::decltype(typeid(a)).name() << std::endl; .. I Mean even if it is not understandable. For example if int is 32432423423403095590353095309530953, then its always gonna be same. So i can easily set a function to return what type the variable is... – amanuel2 Apr 29 '16 at 23:05
  • 2
    @Dsafds woops my mistake, I meant `typeid(decltype(a))`, also `typeid` and `decltype` are keywords, not members of the `std` namespace (i.e. you cannot use the `::` operator before them) It doesn't have to be the same, use `typeid` if you just want to get a runtime-object that identifys the type (the value returned must be unique, but the value of `typeid(..).name()` need not be) – Isaac Apr 29 '16 at 23:08
  • @Isaac i now get error: main.cpp: In function 'int main()': main.cpp:10:24: error: expected primary-expression before 'decltype' std::cout << typeid(decltype(a) << std::endl; ^~~~~~~~ main.cpp:10:24: error: expected ')' before 'decltype' .. For this code: #include #include #include #include #include int main() { int a=5; std::cout << typeid(decltype(a) << std::endl; } – amanuel2 Apr 29 '16 at 23:11
  • @Dsafds sorry another typo, I forgot a `)`, which is exactly what the compiler error message was saying (i.e. I should have written `typeid(decltype(a))`). Also you can't print the result of `typeid(...)`, it's an expression of type `const std::type_info&`, not a string. – Isaac Apr 29 '16 at 23:15
  • It gives me this error now: main.cpp: In function 'int main()': main.cpp:10:14: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream}' and 'const std::type_info') std::cout << typeid(decltype(a)) << std::endl; In file included from /usr/local/include/c++/6.1.0/iostream:39:0, from main.cpp:1: /usr/local/include/c++/6.1.0/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<< Can you please check here, and give me a code snippet? Thanks a bunch Issac. http://coliru.stacked-crooked.com/ – amanuel2 Apr 29 '16 at 23:19
  • @Dsafds, as I said, you cannot print the result of a `typeid(..)` expression, you can ofcoruse print `typeid(...).name()`, but as explained in my answer, that may not be human-readable, unique, or even consistent between executions, it is mostly useless (unless your implementation is reasonable, like Visual C++). The code `std::cout << typeid(decltype(a)).name()` is valid, it will print *something* (anything really, even the empty string). Why do you want to get the name of your variables type anyway? – Isaac Apr 29 '16 at 23:30
  • Ehh @Isaac .. Maybe if i need it in the future..? I was just highly curious. If you are asking me how did i even notice it.. Well i was learning about typedef in C++ Primer Book.. And it just hit me. "Can we identify type of variable"... After couple of researches couldnt get it, so then i decided to ask this question. Oh well, if you cant get a consistant anwser then sadly C++ Wont support it i guess. Ima just be on the lookout for any libaries or functions that may solve this problem and update you if there are any. Anways thank you for your time sir. – amanuel2 Apr 29 '16 at 23:35
  • @Dsafds If you have Boost, you could try `std::cout << boost::typeindex::type_id().pretty_name() << std::endl;` (see [Getting human readable and mangled type names](http://www.boost.org/doc/libs/1_57_0/doc/html/boost_typeindex/examples.html#boost_typeindex.examples.getting_human_readable_and_mangl)) – Isaac Apr 29 '16 at 23:40
  • Also i forgot to mention this Issac. It will be helpfull if i have this for Debugging Purposes. As i have used i do javascript. Well in javascript its as simple as saying.. console.log(typeof a); ..... Only if it were that easy in C++ :( Boost? What is Boost? I guess im learning that at like the end of the C++ Primer Book..? – amanuel2 Apr 29 '16 at 23:40
  • @Dsafs, I havn't read your book, but I doubt it. It is the (most popular?) general purpose C++ library (http://www.boost.org/), it contains lots of things that the standard library is lacking (and other things that would be inapropriete to put there). It is entirely free and open source, and is very platform & compiler independent (it works with most major compilers). – Isaac Apr 29 '16 at 23:44
  • @Isaac Im Not even sure it talks about Boost, because it dosent say so on contents..... Is Boost that helpfull to me in my future C++ Programming? If so, do you have any tutorials/viedos/books you would reccomend a person, so he can be well notified of the "library" Boost? – amanuel2 Apr 30 '16 at 00:03
  • @Dsafds Verry usefull. Though I personanly haven't used it much, I usually just read their website/documentation. Sorry I couldn't be of more help. – Isaac Apr 30 '16 at 00:15
3

I Mean even if it is not understandable. For example if int is 32432423423403095590353095309530953, then its always gonna be same. So i can easily set a function to return what type the variable is...

The results you're getting already fulfill that. Perhaps it would help to explain how exactly the C++ implementation you're using gets the strings you're seeing.

g++ implements typeid(...).name() such that it returns the "ABI mangled" name of the type. This is a special way of representing types that is used in compiled object files and libraries. If you compile C++ code into assembly you'll see "symbols" that identify what function or data the resulting assembly code is related to. For example, take the function:

int foo(double a, char b) {
    return a + b;
}

compile it to assembly, and you'll see something like the following:

_Z3foodc:
.LFB0:
    .cfi_startproc
    movsbl  %dil, %edi
    cvtsi2sd    %edi, %xmm1
    addsd   %xmm1, %xmm0
    cvttsd2si   %xmm0, %eax
    ret
    .cfi_endproc

The first line here is the 'mangled' symbol that is used to identify the function int foo(double,char). It contains "Z3foo" that represents the function name, and then 'd' that represents the type of the first argument and 'c' that represents the type of the second argument. This symbol is used to identify the function in the binary object file, in library indices, by other compiled objects that want to link to this function, etc.

You can also demangle symbols using the c++filt tool. This tool scans through any text you pass it looking for things that conform to the mangling syntax, and converts them into something more like the way those types are named in C++ source code.

g++ implements the Itanium C++ ABI mangling scheme. It's used by most unix platform compilers.

So, back to your code, guess how the type 'int' is represented in these symbols.

The Itanium ABI specifies an additional function for demangling. Here's an example using it.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • Thanks for giving the libary! And also thanks for showing me scary assembly code... :P (OfCourse 3 lines of C++ Code = 10 lines of Assembly Code xD ) – amanuel2 Apr 30 '16 at 00:36
2

The type names are not supposed to be what you expect them to be. See this answer for a way to get the actual type name. Note - it only works on gcc and, with some additional installation, on clang.

With Visual C++ you should call UnDecorateSymbolName, but apparently ints are called int there

Community
  • 1
  • 1
zmbq
  • 38,013
  • 14
  • 101
  • 171
  • 1
    What does ‘https://msdn.microsoft.com/en-us/library/bb384066.aspx’ have to do with anything? Secondly with Visual C++ (at least my version, 14.0.23918) the returned name is valid C++ syntax, and what you would expect, e.g. `typeid(decltype(std::cout)).name()` returns `class std::basic_ostream >` – Isaac Apr 29 '16 at 22:56