I can cast between types by using either from or as:
i64::from(42i32);
42i32 as i64;
What is the difference between those?
as can only be used in a small, fixed set of transformations. The reference documents as:
as can be used to explicitly perform coercions, as
well as the following additional casts. Here *T means either *const T or
*mut T.
Type of e
U
Cast performed by e as U
Integer or Float type
Integer or Float type
Numeric cast
C-like enum
Integer type
Enum cast
bool or char
Integer type
Primitive to integer cast
u8
char
u8 to char cast
*T
*V where V: Sized *
Pointer to pointer cast
*T where T: Sized
Numeric type
Pointer to address cast
Integer type
*V where V: Sized
Address to pointer cast
&[T; n]
*const T
Array to pointer cast
Function item
Function pointer
Function item to function pointer cast
Function item
*V where V: Sized
Function item to pointer cast
Function item
Integer
Function item to address cast
Function pointer
*V where V: Sized
Function pointer to pointer cast
Function pointer
Integer
Function pointer to address cast
Closure **
Function pointer
Closure to function pointer cast
* or T and V are compatible unsized types, e.g., both slices, both the
same trait object.
** only for closures that do not capture (close over) any local variables
Because as is known to the compiler and only valid for certain transformations, it can do certain types of more complicated transformations.
From is a trait, which means that any programmer can implement it for their own types and it is thus able to be applied in more situations. It pairs with Into. TryFrom and TryInto have been stable since Rust 1.34.
Because it's a trait, it can be used in a generic context (fn foo(name: impl Into<String>) { /* ... */ }). This is not possible with as (although see AsPrimitive from the num crate).
When converting between numeric types, one thing to note is that From is only implemented for lossless conversions (e.g. you can convert from i32 to i64 with From, but not the other way around), whereas as works for both lossless and lossy conversions (if the conversion is lossy, it truncates). Thus, if you want to ensure that you don't accidentally perform a lossy conversion, you may prefer using From::from rather than as.
See also:
When should I implement std::convert::From vs std::convert::Into?
Related
The size of pointer is same irrespective of datatype it is pointing to.Then why do we need to declare the datatype it points to?
For example,
int *p; //p will point to an integer data type.
char *p; //p will point to a character
Then,why can't we generalize a pointer declaration like this
pointer p; //where p is an object of pointer class.
TL;DR because, different data types occupy different size in memory and has different alignment requirement.
To elaborate, a pointer variable holds an address which points to some type of data. Without the type associated, there would be no way to dereference the pointer and get the value.
In other words, to access the data pointed to by a pointer, the associated data type must be known.
The size of the pointer itself, has little connection to the actual data it points to.
There exists a pointer , void * which is considered a generic pointer, but then, you can't dereference it, as the result of dereference would attempt to produce an incomplete type. You need to cast it to a complete type to be able to dereference or apply pointer arithmetic on a void pointer.
The reason behind considering void * a generic pointer is as below, quoting from the C11 standard, chapter §6.3.2.3
A pointer to void may be converted to or from a pointer to any object type. A pointer to
any object type may be converted to a pointer to void and back again; the result shall
compare equal to the original pointer.
So, a void * can be used as a generic container which can hold any pointer type, but to make some operation on the pointer (which includes the knowledge of the data type), you need to cast it to a complete type first.
You can generalize pointers using void*. void* is a pointer to some address without any type information associated. However, there is little you can do with these pointers without casting them to an explicit pointer type first.
Consider the following example. It will not compile, because it's impossible to deduce the "value" pointed to by ptr is. You can't even know how many bytes constitute the value.
void print(const void * ptr) {
std::cout << *ptr; // What's the "value" of ptr?
}
Pointer arithmetic.
Explanation:
int arr[] = {4, 6, 9, 10};
int* x = arr;
*(x+0) = 4
*(x+1) = 6
Compiler knows that x+1 is actually x+sizeof(int) and not 1.
To read the second element the compiler has to skip sizeof(int) each time. Without knowing the actual type you can't dereference it and extract the data correctly.
Plus types differ in size, and the compiler needs to know how many bytes to read from the memory pointed to. A char will be 1 byte and int will be more than 1 byte.
A void * pointer can be viewed as a "generalized" pointer.
It can't be dereferenced, though, because by being generic it doesn't point to any one type of object. To actually use a void * pointer and access whatever it's pointing to, you need to cast it to the type of object you're accessing.
And since it doesn't point to any one type of object, there's no proper way to perform pointer arithmetic on a void * pointer.
The size of pointer is same irrespective of data type it is pointing to.
This is not necessarily true - pointers to different types may have different sizes and representations:
A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type.48) Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and alignment requirements. All
pointers to structure types shall have the same representation and alignment requirements
as each other. All pointers to union types shall have the same representation and
alignment requirements as each other. Pointers to other types need not have the same
representation or alignment requirements.
C 2011 Online Draft, §6.2.5 ¶28
The value representation of pointer types
is implementation-defined. Pointers to layout-compatible types shall have the same value representation and
alignment requirements (3.11).
C++ 2014 Working Draft, §3.9.2, ¶3
On most modern desktop and servers they're the same, but don't expect it to be universally true.
Then why do we need to declare the data type it is pointing to?
Pointer arithmetic depends on the pointed-to type - if p points to an object of type T, then p + 1 points to the next object of type T. Since different types have different sizes, you need to know the pointed-to type to compute the offset correctly.
Then,why can't we generalize a pointer declaration like this
pointer p; //where p is an object of pointer class.
You actually can using void*. But the consequence is that all type (and size information) is lost at that point.
You'll have to keep track of that somehow (hard-coded type casts or whatever), to make that useful.
I know that reinterpret_cast is primarily used going to or from a char*.
But I was surprised to find that static_cast could do the same with a void*. For example:
auto foo "hello world"s;
auto temp = static_cast<void*>(&foo);
auto bar = static_cast<string*>(temp);
What do we gain from using reinterpret_cast and char* over static_cast and void*? Is it something to do with the strict aliasing problem?
Generally speaking, static_cast will do cast any two types if one of them can be cast to the other implicitly. That includes arithmetic casts, down-casts, up-casts and cast to and from void*.
That is, if this cast is valid:
void foo(A a);
B b;
foo(b);
Then the both static_cast<B>(a) and static_cast<A>(b) will also be valid.
Since any pointer can be cast implicitly to void*, thus your peculiar behavior.
reinterpret_cast do cast by reinterpreting the bit-pattern of the values. That, as you said in the question, is usually done to convert between unrelated pointer types.
Yes, you can convert between unrelated pointer types through void*, by using two static_cast:
B *b;
A *a1 = static_cast<A*>(b); //compiler error
A *a2 = static_cast<A*>(static_cast<void*>(b)); //it works (evil laugh)!
But that is bending the rules. Just use reinterpret_cast if you really need this.
Your question really has 2 parts:
Should I use static_cast or reinterpret_cast to work with a pointer to the underlying bit pattern of an object without concern for the object type?
If I should use reinterpret_cast is a void* or a char* preferable to address this underlying bit pattern?
static_cast: Converts between types using a combination of implicit and user-defined conversions
In 5.2.9[expr.static.cast]13 the standard, in fact, gives the example:
T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
It leverages the implicit cast:
A prvalue pointer to any (optionally cv-qualified) object type T can be converted to a prvalue pointer to (identically cv-qualified) void. The resulting pointer represents the same location in memory as the original pointer value. If the original pointer is a null pointer value, the result is a null pointer value of the destination type.*
There is however no implicit cast from a pointer of type T to a char*. So the only way to accomplish that cast is with a reinterpret_cast.
reinterpret_cast: Converts between types by reinterpreting the underlying bit pattern
So in answer to part 1 of your question when you cast to a void* or a char* you are looking to work with the underlying bit pattern, reinterpret_cast should be used because it's use denotes to the reader a conversion to/from the underlying bit pattern.
Next let's compare void* to char*. The decision between these two may be a bit more application dependent. If you are going to use a standard library function with your underlying bit pattern just use the type that function accepts:
void* is used in the mem functions provided in the cstring library
read and write use char* as inputs
It's notable that C++ specific libraries prefer char* for pointing to memory.
Holding onto memory as a void* seems to have been preserved for compatibility reasons as pointer out here. So if a cstring library function won't be used on your underlying bit patern, use the C++ specific libraries behavior to answer part 2 of your question: Prefer char* to void*.
I refereed the following link,
Link1
Link 2
In the above link1 it was mentioned in answer that "Pointers are of pointer type".
I just need to know is pointer is a data type or not.
No one has answered that question in single word. It is datatype or not?
This is the second link which i refered says that
Pointers are simply a variable that hold an address so one could argue that a pointer is a data type, but it is not defined as a data type (per "The C Programming Language". Kernighan & Ritchie).
Yes, a pointer is a data type. The purest form of which (mainly talking about C here) is void *. A void * can be used to pass a memory address around (which is what a pointer is), but it can't be dereferenced. Dereferencing a pointer is what you do to get at the data contained at the memory location the pointer is pointing at, which implies that you know what type of data you're reading from the memory. The type determines how much memory will be read, and because a void is "nothing". A void * can be set to point at any block of memory, that can contain any type, so you can cast a void * to any other pointer type (int *, for example), and dereference that, instead.
Each type we have is used to store a specific piece of data (value), we use a char to store a single character, an int to store an integer, double to store double precision decimals and so on. None of these types are used to store locations in memory, apart from pointers. So just like the other types, a pointer is used to store a specific piece of data. And the mother of all pointers is void *.
Sadly, this void * is rather restricted: you can't dereference it, you can't use it for pointer arithmetic (not according to the standard anyway). So C provides you with a series of derived pointer types, that make life easier: char *, int *, double * and so on.
What they are, really, is short-hand for: (char *) void * my_ptr;
Some more attempts at making my point as clearly as possible:
Pointers have their own size, irrespective of the type they're said to point at:
char a_character = 'a'; //type: a char
char *a_char_ptr = &a_character; //memory address, in this case, the one holding a_charachter
The distinction is probably best seen by looking at the sizes of both these vars:
printf("%zu <> %zu\n", sizeof a_character, sizeof a_char_ptr);
The code above will give you something like "1 <> 8" or "1 <> 4", depending on what system you're on. Numbers represent the size, in bytes.
Pointers also have their own printf format specifier: %p:
printf("%c is the value stored at %p\n", *a_char_ptr, (void *) a_char_ptr);
To print the actual memory address (the actual value of a pointer), you are required to cast the pointer to the generic void * type. A void pointer is sort of the generic pointer; it's the pointer that makes no assumptions as to the data it is pointing at. This is what malloc, calloc and realloc return, a generic pointer, that can be set to point at any other type. So what is a char *? It's a generic pointer type, set to point at blocks of memory of 1 byte in size (sizeof(char)). In a sense, a typed pointer, then, is a derived type, but think of it like this: char * is short for (char *) void *my_ptr;
But really, what is a type? The gist of it is that a type is way to determine how data in memory is supposed to be interpreted. A variable of the type char represents a character. A variable of the type int represents an integer. Same applies to pointers: char *x is not of the type char, it's of the type char * (pointer to char). This means that char *x itself is a location in memory we can use to read one or more char values.
I could rant on for a while but TL;TR:
Yes, a pointer is a data type (void * in its purest form). The pure form is quite unusable (because you can't dereference it). Instead of having to cast the pointer every time you decide to use it, C offers the convenience of derived pointer types (like char *, int * and so on). But really, they're pointers, and therefore a data-type in their own right.
You've asked two different questions.
Your title asks "What is the data type of pointer variables?". The answer is simple: a pointer variable is of some pointer type. For example, given:
int *ptr;
ptr is a pointer object, and its type is int*, which is a pointer type.
The body of your question asks whether "a pointer is a data type or not". By any reasonable definition of the phrase "data type", pointer types are data types.
The C standard never defines the phrase "data type", but it does use it (informally) in several places. It happens that none of the uses of the phrase "data type" in the standard refer to pointer types, but that doesn't tell us anything.
The standard says that all types are either function types or object types. Object types are further divided into a number of categories: integer types, array types, structure types, union types, pointer types, etc. A pointer type can be a pointer to an object type or a pointer to a function type. (It can be a pointer to an incomplete object type; as of the 2011 standard, incomplete types are classified as object types.)
Another ambiguity in your question is your use of the word "pointer". The word "pointer" by itself commonly refers to an object of pointer type, but it can also refer to a value of pointer type (for example, the standard says that malloc returns a pointer). It's better to use "pointer" as an adjective rather than as a noun, so you can have:
a pointer type;
a pointer object (an object of pointer type);
a pointer expression (an expression that yields a result of pointer type); or
a pointer value (the value, of pointer type, yielded by a pointer expression).
A pointer type is an object type. A pointer object is an object; an object is defined by the standard as a "region of data storage in the execution environment, the contents of which can represent values". So a pointer object is a region of data storage.
Following your Link 2, some random person on the Internet wrote that "Pointers are simply a variable that hold an address so one could argue that a pointer is a data type, but it is not defined as a data type (per "The C Programming Language". Kernighan & Ritchie)". I don't know whether K&R defines the term "data type"; since this person didn't provide a specific citation, it's difficult to tell without searching the book. But it's the standard, not K&R, that defines the language.
I'm curious: why would you think that a pointer type wouldn't be considered a data type?
For example in the C Standard there is no formal definition of the term data type. There are object types and function types. At the same time pointers are derived types constructed from object and function types.
Thus in general case pointers are data types that is they are data types that are constructed from object and function types.
Also there is definition of term object in the C Standard
3.15
1 object
region of data storage in the execution environment, the contents of which can represent
values
So there is some contradiction in the Standard. On the one hand pointers are objects because they occupy memory and the memory represents their values. So we may say that pointers are object types. On the other hand pointers are considered as derived types from object types.
In my opinion it would be better if there would be explicitly written in the Standard that pointers are derived object types or derived function types.
In any case you may bravely say that pointers are data types!:)
Yes, pointer is a data type and a pointer variable store that pointer data type.
Pointer is a data-type. So we can create pointer variables which can hold the address of memory location.
Pointer types are data types; they store pointer values.
There is no one single pointer type; a pointer to int is a different type from a pointer to char, which is a different type from a pointer to double, which is a different type from a pointer to a 10-element array of int, which is a different type from a pointer to an 11-element array of int, etc.
Different pointer types may have different sizes and representations; the only pointer types that are guaranteed to have the same sizes and representations are void * and char *.
Your question probably refers to the "data type of a pointer", in contrast to the data type of the pointed-to data, which is what one would understand in the first place.
Based on this assumption, then please look at type uintptr_t or void*.
To quote Drew Dorman's answer: "uintptr_t is an unsigned integer type that is capable of storing a pointer. Which typically means that it's the same size as a pointer"
Of course, its size is platform-dependant: 32 bit or 64 bit. So don't transport this variable across platforms of different size.
Please note, to assign it you have to cast from the 'specific' pointer type, to the 'generic' one:
int var = 1;
int* addrOfVar = &var; // pointer to variable
uintptr_t pVar = (uintptr_t)&var;
uintptr_t pVar2 = reinterpret_cast<uintptr_t>(&var); // alternative cast
See a pointer variable stores the address of another variable. And when we access this pointer variable it points to the address of variable which eventually directs us to the data stored inside that variable. Now depending upon the type of data stored inside the original variable we can specify the data type of that pointer variable.
I just need to know is pointer is a data type or not.
All pointer types are data types, but plain "pointer" is not a data type. More precisely, "pointer" is a type modifier that you can apply to absolutely any type. So you can have pointer-to-char, and pointer-to-long, and pointer-to-double, not to mention pointer-to-pointer-to-char, etc.
There are three of these type modifiers in C: pointer-to, array-of, and function-returning. These can be combined in almost any combination. (But, to be sure, a few combinations are invalid. You can't have arrays of functions, or functions returning arrays.)
The thing is Pointer itself is a data type of it's own. It basically store a memory address.
Now it can be used to store a memory address of any variable too.
As an experiment:
I have hypothetical function with signature: void func(void *), where I have to pass an integer value, literally in the code: func(42). It must be done with a literal integer.
Is there a “right” way to pass a integer value, say, “hacked” as an address in a pointer (to address 0x2A for example), and the somehow convert it back to an integer (42 for the 0x2A example). All of this without unexpected behavior?
In short: being able to convert a pointer address into an integer which will hold the number of the address.
Both C and C++ standards explicitly allow for such conversion.
C99 6.3.2.3.5:
An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
C++11 5.2.10.5
A value of integral type or enumeration type can be explicitly converted to a pointer.
Therefore, your call of func((void*)42) should work with all standard-compliant compilers.
What is the, say, most correct way to pass a literal integer to an argument expecting a void pointer, and having the integer untouched in the function?
This way of passing a literal integer as an argument to a function expecting a void* guarantees that the original integer would be untouched in the function, because the argument is passed by value.
It shouldn't be done this way.
You can allocate the value on the stack and then call the function.
Example in C:
int i = 42;
func((void*) (&i));
Example in C++:
int i = 42;
func(reinterpret_cast<void*> (&i));
Otherwise, if you are not sure about the life time of the variable, it can be allocated on the heap using malloc()/free() or new/delete.
If I remember right a C-Style conversion is nothing more than an ordered set of conversions static_cast, dynamic_cast, reinterpret_cast, static_cast...,
consider:
enum NUMBERS
{
NUMBER_ONE,
NUMBER_TWO
};
void Do( NUMBERS a )
{
}
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int a = 1;
Do( a ); //C2664
return 0;
}
a C-Style conversion would do
Do( (NUMBERS)a );
What I would like to know is, what is the correct non C-Style conversion to be made, why?
The correct way would be:
static_cast<NUMBERS>(a)
Because:
8) Integer, floating-point, or enumeration type can be converted to
any enumeration type (the result is unspecified if the value of
expression, converted to the enumeration's underlying type, is not one
of the target enumeration values)
Source: http://en.cppreference.com/w/cpp/language/static_cast
dynamic_cast does runtime checks using RTTI, so it only applies to classes with at least one virtual method.
reinterprest_cast is designed to tell the compiler to treat a specific piece of memory as some different type, without any actual runtime conversions.
static_cast<NUMBERS>(a)
Because the specification for static_cast includes this:
A value of integral or enumeration type can be explicitly converted to
an enumeration type. The value is unchanged if the original value is
within the range of the enumeration values (7.2). Otherwise, the
resulting value is unspecified (and might not be in that range). A
value of floating-point type can also be converted to an enumeration
type. The resulting value is the same as converting the original value
to the underlying type of the enumeration (4.9), and subsequently to
the enumeration type.
static_cast is for generally taking values of one type and getting that value represented as another type. There are about two pages of specification covering all the details, but if you understand that basic idea, then you'll probably know when you want to use static_cast. E.g., if you want to convert an integral value from one integral type to another or if you want to convert a floating point value to an integral value.
dynamic_cast is for working with dynamic types, which is mostly only useful for polymorphic, user-defined types. E.g., convert Base * to Derived * iff the referenced object actually is a Derived.
reinterpret_cast is typically for taking the representation of a value in one type, and getting the value that has the same representation in another type; i.e., type punning (even though a lot of type punning is actually not legal in C++). E.g., if you want to access an integer's storage as an array of char.
const_cast is for adding and removing cv qualifiers (const and volatile) at any level of a type. E.g., int const * volatile **i; const_cast<int volatile ** const *>(i);
static_cast<> is the way to go:
Here's why