快捷搜索:  汽车  科技

c语言中的数据类型强制转换,C类型转换与运行时类型安全检查

c语言中的数据类型强制转换,C类型转换与运行时类型安全检查Any built-in type can be converted to boolean. For objects of those types any value other than 0 gets converted to a boolean value of true and values equal to 0 implicitly convert to a value of false.我们也可以隐式地将double转换为int。但是,一些信息会丢失,编译器会对此发出警告。这称为缩小转换。Some values can be implicitly converted into each other. This is true for all the built-in types. We can convert char to int int to double etc

C语言的数据的类型转换,特别是隐式类型转换,给数据处理带来了极大的便利性,与此同时,也带来了严重的安全隐患。C 对于隐式类型转换,做了一定程度的限制,如void*的隐式转换。

C语言的强制类型转换,简单粗暴,不管何种类型的转换,统一用一个小括号括住目标类型放到数据前面即可,这给错误排查带来了极大的不便,C 继承了C的这一强制类型转换方式,但也额外引入了四个类型转换关键字,对应不同类型的转换情形。

Types can be converted to other types. For example built-in types can be converted to other built-in types.

类型可以转换为其他类型。例如,内置类型可以转换为其他内置类型。

Some values can be implicitly converted into each other. This is true for all the built-in types. We can convert char to int int to double etc.

一些值可以隐式地相互转换。这适用于所有内置类型。我们可以将char转换为int,int转换为double,等等。

We can also implicitly convert double to int. However some information is lost and the compiler will warn us about this. This is called narrowing conversions.

我们也可以隐式地将double转换为int。但是,一些信息会丢失,编译器会对此发出警告。这称为缩小转换。

Any built-in type can be converted to boolean. For objects of those types any value other than 0 gets converted to a boolean value of true and values equal to 0 implicitly convert to a value of false.

任何内置类型都可以转换为boolean。对于这些类型的对象,除0以外的任何值都将转换为布尔值true,而等于0的值将隐式转换为值false。

Conversely a boolean type can be converted to int. The value of true converts to integer value 1 and the value of false converts to integer value of 0.

相反,布尔类型可以转换为int。true的值转换为整数值1,false的值转换为整数值0。

A pointer of any type can be converted to void* type. While we can convert any data pointer to a void pointer we can not dereference the void pointer. To be able to access the object pointed to by a void pointer we need to cast the void pointer to some other pointer type first.

任何类型的指针都可以转换为void*类型。虽然我们可以将任何数据指针转换为void指针,但不能解引用void指针。为了能够访问void指针指向的对象,我们需要首先将void指针转换为其他指针类型。

Arrays are implicitly convertible to pointers. When we assign an array name to the pointer the pointer points at the first element in an array.

数组可以隐式转换为指针。当我们为指针指定数组名时,指针指向数组中的第一个元素。

When used as function arguments the array gets converted to a pointer. More precisely it gets converted to a pointer to the first element in an array. In such cases the array loses its dimension and it is said it decays to a pointer.

当用作函数参数时,数组将转换为指针。更准确地说,它被转换为指向数组中第一个元素的指针。在这种情况下,数组失去了维数(准确地说,是第一维的长度信息),由此表述成它衰减为指针。

We can explicitly convert the value of one type to another.

我们可以显式地将一种类型的值转换为另一种类型。

dynamic_cast Used for conversion of polymorphic types.

用于转换多态类型的dynamic_cast。

static_cast Used for conversion of nonpolymorphic types.

用于转换非多态类型的static_cast。

const_cast Used to remove the const volatile and __unaligned attributes.

用于删除const、volatile和__unaligned属性的const_cast。

reinterpret_cast Used for simple reinterpretation of bits.

用于位的简单重新解释的reinterpret_cast。

1 dynamic_cast Operator

dynamic_cast < type-id > ( expression )

Converts the operand expression to an object of type type-id.

将操作数expression转换为type-id类型的对象。

The type-id must be a pointer or a reference to a previously defined class type or a "pointer to void". The type of expression must be a pointer if type-id is a pointer or an l-value if type-id is a reference.

type-id必须是指针或对先前定义的类类型的引用,或“指向void的指针”。如果type-id是指针,则表达式的类型必须是指针;如果类型id是引用,则表达式的类型必须是左值。

There are two breaking changes in the behavior of dynamic_cast in managed code:

管理代码中dynamic_cast的行为有两个突破性的变化:

dynamic_cast to a pointer to the underlying type of a boxed enum will fail at runtime returning 0 instead of the converted pointer.

对指向装箱枚举的底层类型的指针的dynamic_cast将在运行时失败,返回0而不是转换的指针。

dynamic_cast will no longer throw an exception when type-id is an interior pointer to a value type with the cast failing at runtime. The cast will now return the 0 pointer value instead of throwing.

当type-id是指向值类型的内部指针时,dynamic_cast将不再引发异常,而转换在运行时失败。强制转换现在将返回0指针值,而不是抛出。

If type-id is a pointer to an unambiguous accessible direct or indirect base class of expression a pointer to the unique subobject of type type-id is the result. For example:

如果type-id是指向表达式的明确可访问的直接或间接基类的指针,则结果是指向type-id的唯一子对象的指针。例如:

class B { }; class C : public B { }; class D : public C { }; void f(D* pd) { C* pc = dynamic_cast<C*>(pd); // ok: C is a direct base class // pc points to C subobject of pd B* pb = dynamic_cast<B*>(pd); // ok: B is an indirect base class // pb points to B subobject of pd }

This type of conversion is called an "upcast" because it moves a pointer up a class hierarchy from a derived class to a class it is derived from. An upcast is an implicit conversion.

这种类型的转换称为“向上转换”,因为它将指针从派生类向上移动到基类。“向上转换”是一种隐式转换。

If type-id is void* a run-time check is made to determine the actual type of expression. The result is a pointer to the complete object pointed to by expression. For example:

如果type-id为void*,则执行运行时检查以确定表达式的实际类型。结果是指向表达式所指向的完整对象的指针。例如:

class A {virtual void f();}; class B {virtual void f();}; void f() { A* pa = new A; B* pb = new B; void* pv = dynamic_cast<void*>(pa); // pv now points to an object of type A pv = dynamic_cast<void*>(pb); // pv now points to an object of type B }

If type-id is not void* a run-time check is made to see if the object pointed to by expression can be converted to the type pointed to by type-id.

如果type-id不是void*,则执行运行时检查,以查看表达式指向的对象是否可以转换为类型id指向的类型。

If the type of expression is a base class of the type of type-id a run-time check is made to see if expression actually points to a complete object of the type of type-id. If this is true the result is a pointer to a complete object of the type of type-id. For example:

如果表达式类型是type-id的基类,则执行运行时检查,以查看表达式是否实际指向type-id的完整对象。如果这是真的,则结果是指向type-id的完整对象的指针。例如:

class B {virtual void f();}; class D : public B {virtual void f();}; void f() { B* pb = new D; // unclear but ok B* pb2 = new B; D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D }

This type of conversion is called a "downcast" because it moves a pointer down a class hierarchy from a given class to a class derived from it.

这种类型的转换称为“向下转换”,因为它将指针从给定的类向下移动到从其派生的类。

base type pointer ← derived type pointer; // upcast, here ← means "is a"

derived type pointer ← base type pointer; // downcast, here ← not means "is a"

In cases of multiple inheritance possibilities for ambiguity are introduced.

在多重继承的情况下,引入了歧义的可能性。

c语言中的数据类型强制转换,C类型转换与运行时类型安全检查(1)

A pointer to an object of type D can be safely cast to B or C. However if D is cast to point to an A object which instance of A would result? This would result in an ambiguous casting error. To get around this problem you can perform two unambiguous casts. For example:

指向D类型对象的指针可以安全地转换为B或C。但是,如果将D转换为指向A对象,则会生成A的哪个实例?这将导致不明确的转换错误。为了解决这个问题,可以执行两个明确的强制转换。例如:

class A {virtual void f();}; class B : public A {virtual void f();}; class C : public A {virtual void f();}; class D : public B public C {virtual void f();}; void f() { D* pd = new D; A* pa = dynamic_cast<A*>(pd); // C4540 ambiguous cast fails at runtime B* pb = dynamic_cast<B*>(pd); // first cast to B A* pa2 = dynamic_cast<A*>(pb); // ok: unambiguous }

The following sample creates the base class (struct A) pointer to an object (struct C). This plus the fact there are virtual functions enables runtime polymorphism.

以下示例创建指向对象(结构C)的基类(结构A)指针。这一点,再加上存在虚拟函数的事实,使得运行时多态性成为可能。

The sample also calls a non-virtual function in the hierarchy.

该示例还调用层次结构中的非虚函数。

#include <stdio.h> #include <iostream> void printf_s(char *s) { printf("%s" s); } struct A { virtual void test() { printf_s("in A\n"); } }; struct B : A { virtual void test() { printf_s("in B\n"); } void test2() { printf_s("test2 in B\n"); } }; struct C : B { virtual void test() { printf_s("in C\n"); } void test2() { printf_s("test2 in C\n"); } }; void Globaltest(A& a) { try { C &c = dynamic_cast<C&>(a); // downcast printf_s("in GlobalTest\n"); } catch(std::bad_cast) { printf_s("Can't cast to C\n"); } } int main() { A *pa = new C; // upcast A *pa2 = new B; // upcast pa->test(); // in C B * pb = dynamic_cast<B *>(pa); // downcast but pa from C if (pb) pb->test2(); // test2 in B C * pc = dynamic_cast<C *>(pa2); if (pc) pc->test2(); // C ConStack; Globaltest(ConStack); // in GlobalTest // ↑ A ← C upcast , then to C downcast but from C // ↓ will fail because B knows nothing about C B BonStack; Globaltest(BonStack); // Can't cast to C // ↑ A ← B upcast , then to C downcast but not from C }

Output:

in C test2 in B in GlobalTest Can't cast to C

The bad_cast exception is thrown by the dynamic_cast operator as the result of a failed cast to a reference type.

#include <typeinfo> #include <iostream> class Shape { public: virtual void virtualfunc() const {} }; class Circle: public Shape { public: virtual void virtualfunc() const {} }; using namespace std; int main() { Shape shape_instance; Shape& ref_shape = shape_instance; try { Circle& ref_circle = dynamic_cast<Circle&>(ref_shape); // downcast } catch (bad_cast b) { cout << "Caught: " << b.what(); // Caught: std::bad_cast } } // if not reference being pointer ok

The exception is thrown because the object being cast (a Shape) isn't derived from the specified cast type (Circle). To avoid the exception add these declarations to main:

引发异常的原因是正在转换的对象(形状)不是从指定的转换类型(圆)派生的。为了避免出现异常,请将以下声明添加到main:

Circle circle_instance; Circle& ref_circle = circle_instance;

Then reverse the sense of the cast in the try block as follows:

然后按如下方式反转try块中的转换:

Shape& ref_shape = dynamic_cast<Shape&>(ref_circle); // upcast2 static_cast Operator

static_cast <type-id> ( expression )

Converts an expression to the type of type-id based only on the types that are present in the expression.

仅基于表达式中存在的类型,将expression转换为type-id的类型。

In standard C no run-time type check is made to help ensure the safety of the conversion.

在标准C 中,没有进行运行时类型检查来帮助确保转换的安全性

The static_cast operator can be used for operations such as converting a pointer to a base class to a pointer to a derived class. Such conversions are not always safe.

static_cast运算符可用于将指向基类的指针转换为指向派生类的指针等操作。这种转换并不总是安全的。

In general you use static_cast when you want to convert numeric data types such as enums to ints or ints to floats and you are certain of the data types involved in the conversion. static_cast conversions are not as safe as dynamic_cast conversions because static_cast does no run-time type check while dynamic_cast does. A dynamic_cast to an ambiguous pointer will fail while a static_cast returns as if nothing were wrong; this can be dangerous. Although dynamic_cast conversions are safer dynamic_cast only works on pointers or references and the run-time type check is an overhead.

通常,当您想将数字数据类型(如枚举转换为int或int转换为浮点)并且您确定转换中涉及的数据类型时,可以使用static_cast。static_cast转换不如dynamic_cast转换安全,因为static_cast不执行运行时类型检查,而dynamic_cast执行。对不明确指针的dynamic_cast转换将失败,而static_cast转换将返回,就像没有任何错误一样;这可能很危险。虽然dynamic_cast转换更安全,但dynamic_cast仅适用于指针或引用,并且运行时类型检查是一项开销。

In the example that follows the line D* pd2 = static_cast<D*>(pb); is not safe because D can have fields and methods that are not in B. However the line B* pb2 = static_cast<B*>(pd); is a safe conversion because D always contains all of B.

在下面的示例中,线D*pd2=static_cast<D*>(pb);不安全,因为D可以具有不在B中的字段和方法。但是,线B*pb2=static_cast<B*>(pd);是一个安全的转换,因为D始终包含B的全部

class B {}; class D : public B {}; void f(B* pb D* pd) { D* pd2 = static_cast<D*>(pb); // Not safe // D can have fields and methods that are not in B. B* pb2 = static_cast<B*>(pd); // Safe conversion // D always contains all of B. }

In contrast to dynamic_cast no run-time check is made on the static_cast conversion of pb. The object pointed to by pb may not be an object of type D in which case the use of *pd2 could be disastrous. For instance calling a function that is a member of the D class but not the B class could result in an access violation.

与dynamic_cast相反,没有对pb的static_cast转换进行运行时检查。pb指向的对象可能不是D类型的对象,在这种情况下,使用*pd2可能是灾难性的。例如,调用属于D类而非B类的函数可能会导致访问冲突。

The dynamic_cast and static_cast operators move a pointer throughout a class hierarchy. However static_cast relies exclusively on the information provided in the cast statement and can therefore be unsafe. For example:

dynamic_cast和static_cast运算符在类层次结构中移动指针。然而,static_cast完全依赖于cast语句中提供的信息,因此可能不安全。例如:

class B { public: virtual void Test(){} }; class D : public B {}; void f(B* pb) { D* pd1 = dynamic_cast<D*>(pb); D* pd2 = static_cast<D*>(pb); }

If pb really points to an object of type D then pd1 and pd2 will get the same value. They will also get the same value if pb == 0.

如果pb确实指向D类型的对象,则pd1和pd2将获得相同的值。如果pb==0,它们也将获得相同的值。

If pb points to an object of type B and not to the complete D class then dynamic_cast will know enough to return zero. However static_cast relies on the programmer's assertion that pb points to an object of type D and simply returns a pointer to that supposed D object.

如果pb指向B类型的对象,而不是完整的D类,则dynamic_cast将知道足够的信息,返回零。然而,static_cast依赖于程序员的断言,即pb指向D类型的对象,并简单地返回指向该假定D对象的指针。

Consequently static_cast can do the inverse of implicit conversions in which case the results are undefined. It is left to the programmer to verify that the results of a static_cast conversion are safe.

因此,static_cast可以反转隐式转换,在这种情况下,结果是未定义的。由程序员验证static_cast的结果是否安全。

This behavior also applies to types other than class types. For instance static_cast can be used to convert from an int to a char. However the resulting char may not have enough bits to hold the entire int value. Again it is left to the programmer to verify that the results of a static_cast conversion are safe.

此行为也适用于类类型以外的类型。例如,可以使用static_cast将int转换为char。但是,生成的字符可能没有足够的位来保存整个int值。同样,由程序员验证static_cast的结果是否安全。

The static_cast operator can also be used to perform any implicit conversion including standard conversions and user-defined conversions. For example:

static_cast运算符还可以用于执行任何隐式转换,包括标准转换和用户定义的转换。例如:

typedef unsigned char BYTE; void f() { char ch; int i = 65; float f = 2.5; double dbl; ch = static_cast<char>(i); // int to char dbl = static_cast<double>(f); // float to double i = static_cast<BYTE>(ch); }

The static_cast operator can explicitly convert an integral value to an enumeration type. If the value of the integral type does not fall within the range of enumeration values the resulting enumeration value is undefined.

static_cast运算符可以显式地将整数值转换为枚举类型。如果整数类型的值不在枚举值范围内,则生成的枚举值未定义。

The static_cast operator converts a null pointer value to the null pointer value of the destination type.

static_cast运算符将空指针值转换为目标类型的空指针值。

Any expression can be explicitly converted to type void by the static_cast operator. The destination void type can optionally include the const volatile or __unaligned attribute.

任何表达式都可以通过static_cast运算符显式转换为void类型。目标void类型可以选择包括const、volatile或__unaligned属性。

The static_cast operator cannot cast away the const volatile or __unaligned attributes. See const_cast Operator for information on removing these attributes.

static_cast运算符不能丢弃常量、volatile或未对齐的属性。有关删除这些属性的信息,请参阅const_cast运算符。

C /CLI: Due to the danger of performing unchecked casts on top of a relocating garbage collector the use of static_cast should only be in performance-critical code when you are certain it will work correctly. If you must use static_cast in release mode substitute it with safe_cast in your debug builds to ensure success.

C /CLI:由于在重新定位的垃圾收集器上执行未经检查的强制转换的危险,只有在您确定静态强制转换可以正常工作时,才应该在性能关键代码中使用静态强制转换。如果必须在发布模式下使用static_cast,请在调试版本中用safe_cast替换它,以确保成功。

3 const_cast Operator

Removes the const volatile and __unaligned attribute(s) from a class.

const_cast <type-id> (expression)

A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is identical except for the const volatile and __unaligned qualifiers. For pointers and references the result will refer to the original object. For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member. Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member might produce undefined behavior.

指向任何对象类型的指针或指向数据成员的指针可以显式转换为去除const、volatile和__unaligned限定符的相同类型。对于指针和引用,结果将引用原始对象。对于指向数据成员的指针,结果将引用与原始(uncast)指向数据成员的指针相同的成员。根据被引用对象的类型,通过结果指针、引用或指向数据成员的指针执行的写操作可能会产生未定义的行为。

You cannot use the const_cast operator to directly override a constant variable's constant status.

不能使用const_cast运算符直接重写(override)常量变量的常量状态。

The const_cast operator converts a null pointer value to the null pointer value of the destination type.

const_cast运算符将空指针值转换为目标类型的空指针值。

#include <iostream> using namespace std; class CCTest { public: void setNumber( int ); void printNumber() const; private: int number; }; void CCTest::setNumber( int num ) { number = num; } void CCTest::printNumber() const { cout << "\nBefore: " << number; const_cast< CCTest * >( this )->number--; cout << "\nAfter: " << number; } int main() { CCTest X; X.setNumber( 8 ); X.printNumber(); } /*output Before: 8 After: 7 */

On the line containing the const_cast the data type of the this pointer is const CCTest *. The const_cast operator changes the data type of the this pointer to CCTest * allowing the member number to be modified. The cast lasts only for the remainder of the statement in which it appears.

在包含const_cast的行上,该指针的数据类型为const CCTest*。const_cast运算符将该指针的数据类型更改为CCTest*,允许修改成员号。类型转换只会持续到其出现的语句的剩余部分。

4 reinterpret_cast Operator

Allows any pointer to be converted into any other pointer type. Also allows any integral type to be converted into any pointer type and vice versa.

允许将任何指针转换为任何其他指针类型。还允许将任何整数类型转换为任何指针类型,反之亦然。

reinterpret_cast < type-id > ( expression )

Misuse of the reinterpret_cast operator can easily be unsafe. Unless the desired conversion is inherently low-level you should use one of the other cast operators.

误用reinterpret_cast运算符很容易不安全。除非所需的转换本质上是低级别的,否则应该使用其他cast运算符之一。

The reinterpret_cast operator can be used for conversions such as char* to int* or One_class* to Unrelated_class* which are inherently unsafe.

reinterpret_cast运算符可用于转换,例如char*到int*,或One_class*到Unrelated_class*,这些转换本质上是不安全的。

The result of a reinterpret_cast cannot safely be used for anything other than being cast back to its original type. Other uses are at best nonportable.

reinterpret_转换的结果只能安全地用于转换回其原始类型。其他用途充其量是不可移植的。

The reinterpret_cast operator cannot cast away the const volatile or __unaligned attributes.

reinterpret_cast运算符无法丢弃常量、volatile或未对齐的属性。

The reinterpret_cast operator converts a null pointer value to the null pointer value of the destination type.

reinterpret_cast运算符将空指针值转换为目标类型的空指针值。

One practical use of reinterpret_cast is in a hash function which maps a value to an index in such a way that two distinct values rarely end up with the same index.

reinterpret_cast的一个实际用途是在哈希函数中,该函数将一个值映射到一个索引,使得两个不同的值很少以相同的索引结束。

#include <iostream> using namespace std; // Returns a hash code based on an address unsigned short Hash( void *p ) { unsigned int val = reinterpret_cast<unsigned int>( p ); return ( unsigned short )( val ^ (val >> 16)); } using namespace std; int main() { int a[20]; for ( int i = 0; i < 20; i ) cout << Hash( a i ) << endl; } Output: 64641 64645 64889 64893 64881 64885 64873 64877 64865 64869 64857 64861 64849 64853 64841 64845 64833 64837 64825 64829

The reinterpret_cast allows the pointer to be treated as an integral type. The result is then bit-shifted and XORed with itself to produce a unique index (unique to a high degree of probability). The index is then truncated by a standard C-style cast to the return type of the function.

reinterpret_cast允许将指针视为整数类型。然后对结果进行位移位并与自身异或,以生成唯一索引(在高概率下唯一)。然后,索引通过标准C风格转换为函数返回类型来做截断。

ref

https://docs.microsoft.com/en-us/cpp/cpp/casting

-End-

猜您喜欢: