The author of this code states that (long)tab returns address of the tab. Is it true? If yes, why is it so?
char tab []= "PJC"
cout << " tab = " << tab << ", address: " << (long)tab << "\n" << endl;
Yes, its true. Raw arrays in C/C++ are considered so that their name is the pointer to the first element. So, you can write:
char tab[] = "PJC";
char c = *(tab + 1); // c == J
As pointer is no more than an integer value representing the address in memory, casting pointer to long will print you the address value.
You must be sure that integer would hold all values. Pointers always matches word size, so on 32-bit CPU a pointer is 4 byte, in 64-bit it is 8 byte and you'll need 64-bit integer not to have overflow - what exact type is it depends on the system (may be long long). You can use intptr_t (thanks #Avt) to store pointer values.
Typecasting a variable changes its interpretation, but the actual value remains the same. If you were to print the value with format specifier %x then you'll always get the same result, what typecast you use won't matter.
In this case, tab is a char*, which is nothing but an "address" of the location.
You should cast to void* to get the address. Run following to check
char tab []= "PJC"
cout << " tab = " << tab << ", address1: " << (void*)tab << ", address2: " << (long)tab << "\n" << endl;
But remember that result depends of architecture!
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
#include <iostream>
int main() {
__int64 a = (__int64)"J\x10";
return 0;
}
When I run it, the result is a = 12950320.
How to understand (__int64)"J\x10"?
"J\x10" is a string literal. String literals are arrays of characters with static storage.
__int64 is presumably some type. Based on the name, we can presume that it is some implementation defined (non-standard) 1 64 bits wide signed integer type.
Expression (T)expression is an explicit type conversion colloquially called C-style cast. It performs one or combination of 2 static cast, reinterpret cast or const cast on the operand expression. In this case, the expression converts the value of the string literal expression into the type __int64.
When the value of an array (such as string literal) is used, it is implicitly converted to a pointer to the first element. This is called decaying. The value of a pointer is the memory address where the object is stored.
So, this pointer to the first character of the string literal is converted to the implementation defined integer type. There is no static cast from pointer to integer, so this is a reinterpret cast. Assuming the integer type is large enough to represent the value stored in the pointer (that'll be the case for most systems today, but is not something guaranteed by C++), this conversion maps the address value to some integer value in an implementation defined manner.
If you're still confused: That's fine; the program doesn't make much sense even after understanding what it does.
1 This means that using such type makes the program usable only on limited set of systems that support such special type.
2 It is generally recommended to avoid using C-style casts and instead use one of the specific casts that you intend to use. C-style casts often prevent the compiler from catching obvious bugs. Also, reinterpret cast and const cast should not be used unless you know exactly what it does in the context where you use it and what are the ramifications.
"J\x10" is a string (two chars here, "J" and hexa 10), which by default in C++ is considered as a const char*.
You are trying to cast that const char * to a __int64 value and store it at "a". I think this is a nasty cast.
Running this code several times will shows you that the pointer may vary from to execution to execution (it may show as the same, just due to OS cache).
Another thing to take into account is that __int64 is not a standard type, but a MS one.
Well, that is an explicit type conversion as mentioned in comments. In this case is it relies heavily on programmer knowing what she/he is doing and memory space needed for the conversion.
Let's say we have memory of 2 bytes, and value of those 2 bytes are 0:
int16_t memory = 0; // 16 bits is 2 bytes,
+-----------+-----------+
| 0000-0000 | 0000-0000 |
+-----------+-----------+
Now we can read those 2 bytes individually (byte per byte), or collectivly (as whole 2 byte value). Now lets think of it as an union, and imagine that 2 byte memory space as independant spaces.
union test{
int16_t bytes2;
int8_t bytes[2];
char chars[2];
};
So when we input an value of 20299 into that union we can do next:
union test sub;
sub.bytes2 = 20299;
std::cout << sub.bytes2 << std::endl; // 20299
std::cout << (int)sub.bytes[1] << " " << (int)sub.bytes[0] << std::endl; // 79 75
std::cout << sub.chars[1] << " " << sub.chars[0] << std::endl; // O K
Which works like this:
+-----------+-----------+
| 20 299 |
+-----------+-----------+
| 79 | 75 |
+-----------+-----------+
| 'O' | 'K' |
+-----------+-----------+
But we could do the similar if we ignore several compiler warnings:
sub.bytes2 = (int16_t)'OK'; //CygWin will issue warning about this
std::cout << sub.bytes2 << std::endl; // 20299
std::cout << (int)sub.bytes[1] << " " << (int)sub.bytes[0] << std::endl; // 79 75
std::cout << sub.chars[1] << " " << sub.chars[0] << std::endl; // O K
But if we pass an string "OK" instead of char array 'OK' we will get an error cast from 'const char*' to 'int16_t {aka short int}' loses precision [-fpermissive], and this is because std::string has an extra character \0 that isn't shown marking an end of string. So instead of passing 2 byte constant, we are passing 3 byte constant, and our compiler is issuing an error.
Among memory error that I described earlier there is a lot more going on. Strings are pointers to the memory addres similar in functionality as our union. So any string is an reference to specific memory addres with no information how many bytes does that memory addres occupy (aka length of an string). Now there are headers ( <string> and <cstring> ) that help with that issue in many ways, but that is off topic for this question.
That is an pure basis how casting works, it reads 1 memory as a different type from original integer.
In code you provided we have __int64 a = (__int64)"J\x10" , where __int64 in an 64 bit integer on Windows, and "J\x10" is string literal of specific size that holds value of those letters - but \x10 is an integer of value of 16.
union test{
uint64_t val;
char chars[8];
};
int64_t a = (int64_t)"J\x10";
union test sub;
sub.val = a;
// 4299178052
std::cout << sub.val << std::endl;
// ◦ ◦ ◦ ◦ # # D
std::cout << sub.chars[7] << " "<< sub.chars[6] << " "<< sub.chars[5] << " "<< sub.chars[4] << " " << sub.chars[3] << " " << sub.chars[2] << " "<< sub.chars[1] << " "<< sub.chars[0] << " "<< std::endl;
// 0 0 0 1 0 40 40 44
std::cout <<std::hex << (int)sub.chars[7] << " "<<std::hex << (int)sub.chars[6] << " "<<std::hex << (int)sub.chars[5] << " "<<std::hex << (int)sub.chars[4] << " "<<std::hex << (int)sub.chars[3] << " " <<std::hex << (int)sub.chars[2] << " " <<std::hex << (int)sub.chars[1] << " "<<std::hex << (int)sub.chars[0] << " "<< std::endl;
But as you can see I didn't get the same result as you, and the issues range in more than this. __int64 is an Virtual Studio only type only, and it is corresponding to the long long, how constant memory reads is prone to errors of referencing, and in general it is bad code that should be discouraged.
This kind of behaviour, especially with VS type only is not easy to understand, and it doesn't have to have same result, it can also raise numerous errors if copy/pasted that are hard to decipher if OS and IDE brands are unknown or not present in metadata. You should always use known aliases and references
I defined an struct based on bytes, with size of 3 bytes. (1 packetID and 2 packetSize) I checked the size with sizeof function, and it works well:
#pragma pack(1)
typedef struct ENVIRONMENT_STRUCT{
unsigned char packetID[1];
unsigned char packetSize[2];
}
I created a variable and reserved memory like this:
ENVIRONMENT_STRUCT * environment_struct = new ENVIRONMENT_STRUCT();
For now I want to initialize environment_struct.
The problem is about I am trying to initialize this struct by attribute, just like this:
*environment_struct->packetSize = 100;
But when I checked this value, using:
std::cout << "Packet Size: " << environment_struct->packetSize << endl;
Result: Packet Size: d
Expected result: Packet Size: 100
If i will work with numbers, Should I define the struct using csdint library? For example, u_int8 and this type of variable.
When you do
ENVIRONMENT_STRUCT * environment_struct = new ENVIRONMENT_STRUCT();
you initialize packetSize to be {0, 0}. Then
*environment_struct->packetSize = 100;
turns the array into {100, 0}. Since the array is a character array when you send it to cout with
std::cout << "Packet Size: " << environment_struct->packetSize << endl;
it treats it as a c-string and prints out the string contents. Since you see d that means your system is using ascii as the character 'd' has an integer representation of 100. To see the 100 you need to cast it to an int like
std::cout << "Packet Size: " << static_cast<int>(*environment_struct->packetSize) << endl;
Do note that since packetSize is an array of two chars you can't actually assign a single value that takes up that whole space. If you want this then you need to use fixed width types like
typedef struct ENVIRONMENT_STRUCT{
uint8_t packetID; // unsigned integer that is exactly 8 bits wide. Will be a compiler error if it does not exist
uint16_t packetSize; // unsigned integer that is exactly 16 bits wide. Will be a compiler error if it does not exist
};
int main()
{
ENVIRONMENT_STRUCT * environment_struct = new ENVIRONMENT_STRUCT();
environment_struct->packetSize = 100;
std::cout << "Packet Size: " << environment_struct->packetSize << std::endl;
}
Let's first consider what *environment_struct->packetSize = 100; does. It sets the first byte of ENVIRONMENT_STRUCT::packetSize to 100. A more conventional syntax to do this is: environment_struct->packetSize[0] = 100.
There's really no way to initialize the struct in a way for the expression std::cout << environment_struct->packetSize to result in the output of 100. Let us consider what that does. environment_struct->packetSize is an array, which in this case decays to a pointer to first element. Character pointers inserted into character streams are interpreted as null terminated character strings. Luckily, you had valueinitialized the second byte of environment_struct->packetSize, so your array is indeed null terminated. The value of the first byte is interpreted as an encoded character. On your system encoding, it happens that d character is encoded as value 100.
If you wish to print the numeric value of the first byte of environment_struct->packetSize, which you had set to 100, you can use:
std::cout << "Packet Size: " << (int)environment_struct->packetSize[0] << endl;
You get this result as you tries to print a character symbol not an integer.
To fix it just cast the value or declare it as integer depending on your needs.
Cast example:
std::cout << "Packet Size: " << static_cast<int>(*environment_struct->packetSize) << std::endl;
As packetSize is declared as char-type, it's being output as a character. (ASCII code of character 'd' is 100...)
Try casting it to an integer-type:
std::cout << "Packet Size: " << (int)environment_struct->packetSize << endl;
Alternatively, since you appear to want to store the number as a 2-byte type, you could avoid such casting and simply declare packetSize as unsigned short. This will be interpreted by cout as an integer-type.
I have this program:
#include <iostream>
#include <conio.h>
#include <string.h>
using namespace std;
int main()
{
char char1[30] = "ExtraCharacter", char2[30] = "Character", *p;
p = strstr(char1, char2);
cout << "p: " << p << endl;
cout << "char1: " << char1 << endl;
cout << "(p-char1): " << (p-char1) << endl;
return 0;
}
When I run it, I get:
p: Character
char1: ExtraCharacter
(p-char1): 5
as expected.
But this is not the problem, I'm not sure why "Character" - "ExtraCharacter" is an integer (5)? Perhaps not an integer, but a number/digit anyways.
Actually I don't understand why is "Character" stored in p, and not the memory address.
If I understood well from a book, strstr() returns a memory address, shouldn't it be more like a strange value, like a hex (0x0045fe00) or something like that? I mean, it's cout << p not cout << *p to display the actual value of that memory address.
Can someone explain me how it works?
P.S.: I apologize if the title is not that coherent.
But this is not the problem, I'm not sure why "Character" - "ExtraCharacter" is an integer (5)?
You subtract one pointer from another and result - number, distance from char char1 points to to char p points to. This is how pointer arithmetic works.
Note: this subtraction is only valid when both pointers point to the same array (or behind the last element), which is the case in your code, but you need to be careful. For example if strstr() does not find susbtring then it would return nullptr and your subtraction will have UB. So at least check p before subtracting (and passing nullptr to std::cout would have UB as well)
If I understood well from a book, strstr() returns a memory address, shouldn't it be more like a strange value, like a hex (0x0045fe00) or something like that? I mean, it's cout << p not cout << *p to display the actual value of that memory address.
Yes p is a pointer aka memory adress. std::ostream has special rule how to print pointers to char - as strings, because strings in C stored that way. If you want to see it as a pointer just cast it:
std::cout << static_cast<void *>( p );
then you will see it as an address.
To display address, you have to cast char* to void*:
std::cout << "p: " << static_cast<const void*>(p) << std::endl;
Demo
For std::basic_ostream (type of cout), character and character string arguments (e.g., of type char or const char*) are handled by the non-member overloads of operator<< which are being treated as strings. char[30] will be decayed to const char* argument and basic_ostream will output the null terminated string at the address of the pointer.
As for (p-char1), the result of subtracting two pointers is a std::ptrdiff_t. It is an implementation-defined signed integer. That's why the output is 5
I'm new to C++ and is trying to learn the concept of pointer. When I tried to print out the value of pStart, I was expecting its value to be the address of text[0] in hexdecimal (e.g. something like 0x7fff509c5a88). However, the actual value printed out is abcdef.
Could someone explain it to me why this is the case? What parts am I missing?
char text[] = "abcdef";
char *pStart = &text[0];
cout << "value of pStart: " << pStart << endl;
Iostreams provide an overload that assumes a pointer to char points to a NUL-terminated (C-style) string, and prints out the string it points to.
To get the address itself to print out, cast it to a pointer to void instead:
cout << "value of pStsart: " << (void *)pStart << "\n";
Note that you don't really need pStart here at all though. The name of an array (usually, including this case) evaluates to the address of the beginning of the array, so you can just print it directly:
cout << "address of text: " << (void *)text << "\n";
Get out of the habit of using endl as well. It does things you almost certainly don't realize and almost never want.
I need to track my current location in a data buffer (which will be used as a packet), so I am using two variables, bufferLoc and dataBuffer.
char dataBuffer[8192];
char** bufferLoc;
I am pointing to the starting location of dataBuffer with bufferLoc. But incrementing bufferLoc does not affect its physical address in memory.
bufferLoc = (char**)&dataBuffer;
cout << &bufferLoc << endl;
bufferLoc++;
cout << &bufferLoc << endl;
These two prints will output the same location. Does my error have to do with type casting, with bufferLoc itself, or something completely different?
Thanks for your help.
If your intention is to scan through dataBuffer one byte at a time, then the second variable should be a pointer, not a pointer to a pointer.
char* bufferLoc;
then print it out without the ampersand:
cout << (unsigned int *)bufferLoc << endl;
note that cout will try to print your variable as text unless you cast to an unsigned int*
cout << &bufferLoc << endl;
prints the address of bufferLoc. This address is always the same. You can print the value stored in bufferLoc:
cout << bufferLoc << endl;
this value is the address of dataBuffer initially, when you increment it, it will be 4 bytes greater in the second print statement.
dataBuffer itself stores a pointer to a char array of 8192 bytes. What you want to do is to get this value:
char *bufferLoc = dataBuffer;
and increment this value. Note that type of bufferLoc is a pointer to a char array (just as dataBuffer). After assigning the address stored in dataBuffer to bufferLoc, you can print the first element: like this: cout << bufferLoc[0] << end.