{"id":104618,"date":"2020-12-30T07:00:00","date_gmt":"2020-12-30T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104618"},"modified":"2020-12-30T07:40:24","modified_gmt":"2020-12-30T15:40:24","slug":"20201230-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201230-00\/?p=104618","title":{"rendered":"Why are the C and C++ compilers giving me error messages about int when my code doesn&#8217;t mention int?"},"content":{"rendered":"<p>You&#8217;re trying to get your code to compile without errors, and you&#8217;re working through the error list, and then you get to some error message that complains about <code>int<\/code> when your code never mentions <code>int<\/code>:<\/p>\n<pre>void f()\r\n{\r\n  const char* p = get_user_name();\r\n}\r\n<\/pre>\n<p>The errors are<\/p>\n<pre>test.cpp(3): error C2065: 'get_user_name' : undeclared identifier\r\n<\/pre>\n<p>Okay, I expected that one. Forgot to declare <code>const char* get_user_name();<\/code>. I know how to fix that: Add the declaration.<\/p>\n<p>Now to the next error:<\/p>\n<pre style=\"white-space: pre-wrap;\">test.cpp(3) : error C2440: 'initializing' : cannot convert from 'int' to 'const char *'\r\n  Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast\r\n<\/pre>\n<p>What&#8217;s this about converting an <code>int<\/code> to a <code>const char *<\/code>? There are no <code>int<\/code>s in this code anywhere!<\/p>\n<p>What you&#8217;re seeing is a cascade error. The compiler didn&#8217;t see any declaration for <code>get_user_name()<\/code>, so it had two choices.<\/p>\n<ol>\n<li>Stop the compilation right there.<\/li>\n<li>Keep going to see if there are any more errors.<\/li>\n<\/ol>\n<p>Nearly all compilers go for the second option, because duh. But this means that the compiler needs to recover from its error state into some sort of valid state.<\/p>\n<p>A popular choice for recovery is to assume that all undeclared variables are of type <code>int<\/code>, and all undeclared functions return <code>int<\/code>. This is probably for historical reasons, because in the original C language, there were a lot of places where if you didn&#8217;t specify a type, you got <code>int<\/code>. In particular, you could call a function without declaring it, and the function was assumed to return <code>int<\/code>.<\/p>\n<p>In those cases, the compiler recovers by inserting the declaration<\/p>\n<pre>extern int get_user_name();\r\n<\/pre>\n<p>and resuming. And that leads to the second error message: You&#8217;re trying to assign an <code>int<\/code> to a <code>const char *<\/code>.<\/p>\n<p>Of course, that <code>int<\/code> is not your <code>int<\/code>. It&#8217;s the <code>int<\/code> that the compiler&#8217;s error recovery machinery manufactured out of nowhere in a futile attempt to get the compiler back on track.<\/p>\n<p>Sometimes, the compiler is nice enough to tell you what its error recovery is doing, with a message like &#8220;undeclared identifier, assuming int.&#8221; But sometimes it just plows forward without telling you what recovery steps it took.<\/p>\n<p>At some point\u00b9 between Visual Studio 6 and 2017,\u00b2 the Microsoft compiler changed the way it recovers from undefined identifiers. Instead of assuming that they are <code>int<\/code>, it treats them as a hypothetical type called <code>unknown-type<\/code>.<\/p>\n<p>So if you see compiler errors about <code>unknown-type<\/code>, then it&#8217;s the same problem: The compiler encountered an earlier error and created some imaginary declarations to try to get itself back on track so it can report additional errors.<\/p>\n<p>I hope at least that the name <code>unknown-type<\/code> makes it clearer what happened.<\/p>\n<p>\u00b9 I was too lazy to install every version of Visual Studio between 6 and 2017. You can get your refund at the counter over there.<\/p>\n<p>\u00b2 Depending on how you count, this means that it&#8217;s a range of 9 versions or 2011 versions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s a manufactured <CODE>int<\/CODE>.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-104618","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It&#8217;s a manufactured <CODE>int<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104618","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=104618"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104618\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=104618"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104618"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104618"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}