1"use strict";(self.webpackChunkc_c_notes=self.webpackChunkc_c_notes||[]).push([[7321],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>m});var a=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function p(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),s=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=s(n),y=i,m=d["".concat(l,".").concat(y)]||d[y]||g[y]||o;return n?a.createElement(m,r(r({ref:t},c),{},{components:n})):a.createElement(m,r({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=y;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[d]="string"==typeof e?e:i,r[1]=p;for(var s=2;s<o;s++)r[s]=n[s];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}y.displayName="MDXCreateElement"},5921:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>g,frontMatter:()=>o,metadata:()=>p,toc:()=>s});var a=n(8168),i=(n(6540),n(5680));const o={sidebar_position:8,id:"casting",title:"Casting (type conversion)",hide_title:!1,hide_table_of_contents:!1,sidebar_label:"Casting",description:"How type conversion works in C++.",slug:"/cpp/casting",custom_edit_url:null},r=void 0,p={unversionedId:"cpp/casting",id:"cpp/casting",title:"Casting (type conversion)",description:"How type conversion works in C++.",source:"@site/docs/cpp/casting.md",sourceDirName:"cpp",slug:"/cpp/casting",permalink:"/docs/cpp/casting",draft:!1,editUrl:null,tags:[],version:"current",lastUpdatedAt:1747598548,formattedLastUpdatedAt:"May 18, 2025",sidebarPosition:8,frontMatter:{sidebar_position:8,id:"casting",title:"Casting (type conversion)",hide_title:!1,hide_table_of_contents:!1,sidebar_label:"Casting",description:"How type conversion works in C++.",slug:"/cpp/casting",custom_edit_url:null},sidebar:"tutorialSidebar",previous:{title:"Operators",permalink:"/docs/cpp/operators"},next:{title:"Header files and libraries",permalink:"/docs/cpp/header-files-and-libraries"}},l={},s=[{value:"Implicit type conversion",id:"implicit-type-conversion",level:2},{value:"Output:",id:"output",level:4},{value:"Casting (explicit type conversion)",id:"casting-explicit-type-conversion",level:2},{value:"Output:",id:"output-1",level:4},{value:"C-style type casting",id:"c-style-type-casting",level:3},{value:"Function notation",id:"function-notation",level:3},{value:"<code>static_cast</code>",id:"static_cast",level:3}],c={toc:s},d="wrapper";function g(e){let{components:t,...n}=e;return(0,i.yg)(d,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("p",null,"C++ is a ",(0,i.yg)("strong",{parentName:"p"},"statically-typed language"),". This means that the programmer has to explicitly declare\nthe data type when they create a piece of data (variables, parameters, return values\u2026); in this way,\nthe type of some data is known at ",(0,i.yg)("em",{parentName:"p"},"compile-time")," instead of at ",(0,i.yg)("em",{parentName:"p"},"run-time"),". Usually, these\ntypes are also fixed: an ",(0,i.yg)("inlineCode",{parentName:"p"},"int")," variable, for example, will keep that type for the lifetime of\nthe program and it won't
1change its type once assigned."),(0,i.yg)("p",null,"Fortunately, C++ allows us to convert data of one type to that of another. This feature is really\nhandy, especially when working with different data types at the same time."),(0,i.yg)("p",null,"Conversion can happen in two ways, one ",(0,i.yg)("em",{parentName:"p"},"implicit")," and one ",(0,i.yg)("em",{parentName:"p"},"explicit"),"."),(0,i.yg)("h2",{id:"implicit-type-conversion"},"Implicit type conversion"),(0,i.yg)("p",null,"Implicit type conversion (also called ",(0,i.yg)("em",{parentName:"p"},"automatic type conversion")," or ",(0,i.yg)("em",{parentName:"p"},"coercion"),") is automatically\nperformed by the compiler and we don't need to write anything in particular to make that happen.\nImplicit type conversion is often associated with ",(0,i.yg)("strong",{parentName:"p"},"narrowing conversion"),", a case where the\ndestination data type is smaller (meaning that it is capable of storing less information) than\nthe source data type and some data is lost in the process of value transfer. In other words,\nnarrowing conversion happens when data of a larger type is converted to data of a smaller type",(0,i.yg)("sup",{parentName:"p",id:"fnref-1"},(0,i.yg)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),"."),(0,i.yg)("p",null,"Let's see an example of implicit and narrowing type conversion:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-cpp",metastring:'title="implicit-narrowing-type-conversion.cpp" {8}',title:'"implicit-narrowing-type-conversion.cpp"',"{8}":!0},'#include <iostream>\nusing namespace std;\n\nint main() {\n float decimalVar = 2.99;\n\n // implicit and narrowing type conversion\n int integerVar = decimalVar;\n\n cout << "decimalVar = " << decimalVar << endl;\n cout << "integerVar = " << integerVar << endl;\n\n return 0;\n}\n')),(0,i.yg)("h4",{id:"output"},"Output:"),(0,i.yg)("div",{class:"output"},(0,i.yg)("code",{class:"output"},"decimalVar = 2.99",(0,i.yg)("br",null),"integerVar = 2")),(0,i.yg)("p",null,"In the above program, we try to put the value of a ",(0,i.yg)("inlineCode",{parentName:"p"},"float")," type variable with decimal digits in a\nvariable of type ",(0,i.yg)("inlineCode",{parentName:"p"},"int"),". This doesn't cause an error in the compilation and we are allowed to do\nit, but by doing so we are losing information. Also, note that C++ doesn't round to 3 but removes\ncompletely all the decimal digits. "),(0,i.yg)("p",null,"We don't explicitly express to the compiler how to behave and the final result stored in\n",(0,i.yg)("inlineCode",{parentName:"p"},"integerVar")," will contain only a narrower amount of information because it can't handle decimal\ndigits. That's why this conversion is implicit and narrowing (information-losing)."),(0,i.yg)("admonition",{title:"Advanced",type:"note"},(0,i.yg)("p",{parentName:"admonition"},"Some type conversions are always safe to make (such as int to double), whereas others may result\nin the value being changed during conversion (such as double to int). Unsafe implicit conversions\nwill typically either generate a compiler warning or (in the case of brace initialization) an\nerror",(0,i.yg)("sup",{parentName:"p",id:"fnref-2"},(0,i.yg)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2")),"."),(0,i.yg)("p",{parentName:"admonition"},"To be sure not to make involuntary narrowing errors, we can use brace (or list) initialization.\nUsing that:"),(0,i.yg)("ul",{parentName:"admonition"},(0,i.yg)("li",{parentName:"ul"},"An integer cannot be converted to another integer that cannot hold its value. For example,\n",(0,i.yg)("inlineCode",{parentName:"li"},"char")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"int")," is allowed, but not ",(0,i.yg)("inlineCode",{parentName:"li"},"int")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"char"),"."),(0,i.yg)("li",{parentName:"ul"},"A floating-point value cannot be converted to another floating-point type that cannot hold its\nvalue. For example, ",(0,i.yg)("inlineCode",{parentName:"li"},"float")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"double")," is allowed, but not ",(0,i.yg)("inlineCode",{parentName:"li"},"double")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"float"),"."),(0,i.yg)("li",{parentName:"ul"},"A floating-point value cannot be converted to an integer type."),(0,i.yg)("li",{parentName:"ul"},"An integer value cannot be converted to a floating-point type.")),(0,i.yg)("p",{parentName:"admonition"},"See this ",(0,i.yg)("a",{parentName:"p",href:"https://stackoverflow.com/a/18222927/13122341"},"answer")," on Stack Overflow for more info.")),(0,i.yg)("p",null,"The rule to keep in mind to avoid this problem is that the destination data type cannot be\nsmaller than the source data type. This conversion is called ",(0,i.yg)("strong",{parentName:"p"},"widening conversion"),"."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-cpp"},"int main() {\n int integerVar = 4;\n float decimalVar;\n // int value 'integerVar' is implicitly converted to type float\n decimalVar = integerVar; // decimalVar = 4.0000000\n \n return 0;\n}\n")),(0,i.yg)("h2",{id:"casting-explicit-type-conversion"},"Casting (explicit type conversion)"),(0,i.yg)("p",null,"Casting is the act of telling the compiler the type of the resulting conversion. It's the\nprogrammer's intervention to manually change data from one type to another explicitly."),(0,i.yg)("p",null,"To see casting in action, let's first try to take the average between three integer values ",(0,i.yg)("inlineCode",{parentName:"p"},"a"),",\n",(0,i.yg)("inlineCode",{parentName:"p"},"b")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"c")," with the simple formula: ",(0,i.yg)("strong",{parentName:"p"},(0,i.yg)("inlineCode",{parentName:"strong"},"average = sumOfValues / numberOfValues")),"."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-cpp",metastring:'title="int-average.cpp" {14}',title:'"int-average.cpp"',"{14}":!0},'#include <iostream>\nusing namespace std;\n\nint main() {\n int a, b, c;\n int sum;\n\n cout << "Insert 3 values: " << endl;\n cin >> a;\n cin >> b;\n cin >> c;\n\n sum = a+b+c;\n float average = sum/3;\n\n cout << "The average is: " << average << endl;\n\n return 0;\n}\n')),(0,i.yg)("h4",{id:"output-1"},"Output:"),(0,i.yg)("code",{class:"output"},"3"),(0,i.yg)("p",null,"Supposing to insert 2, 4 and 5, the average we expect to see in the output should be somewhere\naround ",(0,i.yg)("inlineCode",{parentName:"p"},"3.6666"),". However, the output we get is just ",(0,i.yg)("strong",{parentName:"p"},(0,i.yg)("inlineCode",{parentName:"strong"},"3")),"."),(0,i.yg)("p",null,"The reason for that unexpected behavior has to do with data types.\nWe are doing a division
1where the resulting quotient is a value with decimal digits (",(0,i.yg)("inlineCode",{parentName:"p"},"3.6666"),").\nWe are storing that quotient in a ",(0,i.yg)("inlineCode",{parentName:"p"},"float")," variable, so those digits should be preserved, ",(0,i.yg)("em",{parentName:"p"},"however"),"\nsince the division happens between two ",(0,i.yg)("inlineCode",{parentName:"p"},"int")," values, the returned value keeps that ",(0,i.yg)("inlineCode",{parentName:"p"},"int")," type,\ntruncating any decimal place (integral values can't hold fractions and only the non-fractional\ncomponent is retained).In standard C++, no run-time type check is made to help ensure the safety\nof the conversion",(0,i.yg)("sup",{parentName:"p",id:"fnref-3"},(0,i.yg)("a",{parentName:"sup",href:"#fn-3",className:"footnote-ref"},"3")),", therefore if we try to divide two or more ",(0,i.yg)("inlineCode",{parentName:"p"},"int")," variables or numbers we\ncan't get a ",(0,i.yg)("inlineCode",{parentName:"p"},"float")," value as a result."),(0,i.yg)("p",null,"The only way to obtain a different type as output is by doing casting."),(0,i.yg)("h3",{id:"c-style-type-casting"},"C-style type casting"),(0,i.yg)("p",null,"There are many ways to do casting conversion, but the most common (and the one that we will use\nfor our programs) is the ",(0,i.yg)("strong",{parentName:"p"},"C-style type casting")," (also known as cast notation)."),(0,i.yg)("p",null,"That method consists of putting the data type we want in return by the conversion before the\nidentifier of the original data or a calculation and surrounding that type by a pair of\nround brackets ",(0,i.yg)("inlineCode",{parentName:"p"},"(")," ",(0,i.yg)("inlineCode",{parentName:"p"},")"),". Of course the resulting conversion has to be stored in another variable\nwith the proper type or printed. It sounds complicated but it really isn't. Look at this example:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-cpp"},"// destinationDataType identifier = (targetDataType) variableOrExpression;\nfloat average = (float) sum/3;\n")),(0,i.yg)("p",null,"See that ",(0,i.yg)("inlineCode",{parentName:"p"},"(float)"),"? It's the ",(0,i.yg)("strong",{parentName:"p"},"explicit casting"),". It explicitly tells the compiler that we want the\nresult of the expression to be of type ",(0,i.yg)("inlineCode",{parentName:"p"},"float"),". Replace this line of code with line 14 in the\nprevious program and run it again. "),(0,i.yg)("admonition",{type:"success"},(0,i.yg)("p",{parentName:"admonition"},"We have now fixed the problem!")),(0,i.yg)("p",null,"In this example, when the compiler performs the division, ",(0,i.yg)("em",{parentName:"p"},"dividend")," and ",(0,i.yg)("em",{parentName:"p"},"divisor")," are both ",(0,i.yg)("inlineCode",{parentName:"p"},"int"),"\nbut we have explicitly expressed that the quotient has to be of type ",(0,i.yg)("inlineCode",{parentName:"p"},"float"),", so everything works\nfine."),(0,i.yg)("admonition",{type:"note"},(0,i.yg)("p",{parentName:"admonition"},"In this case we could also write ",(0,i.yg)("inlineCode",{parentName:"p"},"float average = sum/3.0;")," or ",(0,i.yg)("inlineCode",{parentName:"p"},"float average = (float)sum/(float)3;")),(0,i.yg)("p",{parentName:"admonition"},"It's sufficient to use a cast on one of the operands, but it doesn't hurt if we cast both.")),(0,i.yg)("h3",{id:"function-notation"},"Function notation"),(0,i.yg)("p",null,"A variation of C-style type casting is the function notation, where the syntax for the\nparenthesis is inverted: we put the data type before the expression and then the latter in\nparentheses ",(0,i.yg)("inlineCode",{parentName:"p"},"(")," ",(0,i.yg)("inlineCode",{parentName:"p"},")"),", like so: ",(0,i.yg)("inlineCode",{parentName:"p"},"dataType(variable);"),"."),(0,i.yg)("h3",{id:"static_cast"},(0,i.yg)("inlineCode",{parentName:"h3"},"static_cast")),(0,i.yg)("p",null,(0,i.yg)("inlineCode",{parentName:"p"},"static_cast")," is one of the four ",(0,i.yg)("em",{parentName:"p"},"named casts")," available in C++ and it's a type casting operator.\nIt forces one data type to be converted into another data type. The ",(0,i.yg)("inlineCode",{parentName:"p"},"static_cast")," operator\ntakes an expression as input and returns the evaluated value converted to the type specified\ninside the angled brackets",(0,i.yg)("sup",{parentName:"p",id:"fnref-4"},(0,i.yg)("a",{parentName:"sup",href:"#fn-4",className:"footnote-ref"},"4")),". The syntax is: ",(0,i.yg)("inlineCode",{parentName:"p"},"static_cast<dataType>(variable);"),"."),(0,i.yg)("div",{className:"footnotes"},(0,i.yg)("hr",{parentName:"div"}),(0,i.yg)("ol",{parentName:"div"},(0,i.yg)("li",{parentName:"ol",id:"fn-1"},(0,i.yg)("a",{parentName:"li",href:"https://www.programiz.com/cpp-programming/type-conversion"},"Programiz.com - C++ Type Conversion"),(0,i.yg)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,i.yg)("li",{parentName:"ol",id:"fn-2"},(0,i.yg)("a",{parentName:"li",href:"https://www.learncpp.com/cpp-tutorial/introduction-to-type-conversion-and-static_cast/"},"LearnCpp.com - Introduction to type conversion and static_cast"),
1(0,i.yg)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")),(0,i.yg)("li",{parentName:"ol",id:"fn-3"},(0,i.yg)("a",{parentName:"li",href:"https://docs.microsoft.com/en-us/cpp/cpp/static-cast-operator?view=msvc-170"},"docs.microsoft.com - static_cast Operator"),(0,i.yg)("a",{parentName:"li",href:"#fnref-3",className:"footnote-backref"},"\u21a9")),(0,i.yg)("li",{parentName:"ol",id:"fn-4"},(0,i.yg)("a",{parentName:"li",href:"https://www.learncpp.com/cpp-tutorial/explicit-type-conversion-casting-and-static-cast/"},"LearnCpp.com - Explicit type conversion (casting) and static_cast"),(0,i.yg)("a",{parentName:"li",href:"#fnref-4",className:"footnote-backref"},"\u21a9")))))}g.isMDXComponent=!0}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.