I have a class below:
class A
{
public:
double a;
float b;
double c;
};
I want to print data member offset in class, than I use:
double A::* pm = &A::a;
cout << *(int *)&pm << endl;
It works well and print '0', but I don't want to use intermediate variable pm
cout << *(int *)&A::a << endl;
I got compile error with : Invalid type conversion
With offset is assumed that you refer offset in bytes.
You could try this solution:
(size_t) &(((A*)0)->a) // prints 0
Actually this is the implementation of the macro offsetof as WhozCraig suggested.
...
cout << "A::a => " << (size_t) &(((A*)0)->a)
<< "\nA::b => " << (size_t) &(((A*)0)->b)
<< "\nA::c => " << (size_t) &(((A*)0)->c);
...
Combined with your data, previous snippet will print:
A::a => 0
A::b => 8
A::c => 16
Related
The code successfully compiles it but I can't understand why, for certain values of number, the program crashes and for other values it doesn't. Could someone explain the behavior of adding a long int with a char* that the compiler uses?
#include <iostream>
int main()
{
long int number=255;
std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
number=15155;
std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
return 0;
}
Test results:
Value 1 : >
Value 2 : Segmentation fault
Note: I'm not looking for a solution on how to add a string with a number.
In C++, "" is a const char[1] array, which decays into a const char* pointer to the first element of the array (in this case, the string literal's '\0' nul terminator).
Adding an integer to a pointer performs pointer arithmetic, which will advance the memory address in the pointer by the specified number of elements of the type the pointer is declared as (in this case, char).
So, in your example, ... << ("" + number) << ... is equivalent to ... << &""[number] << ..., or more generically:
const char *ptr = &""[0];
ptr = reinterpret_cast<const char*>(
reinterpret_cast<const uintptr_t>(ptr)
+ (number * sizeof(char))
);
... << ptr << ...
Which means you are going out of bounds of the array when number is any value other than 0, thus your code has undefined behavior and anything could happen when operator<< tries to dereference the invalid pointer you give it.
Unlike in many scripting languages, ("" + number) is not the correct way to convert an integer to a string in C++. You need to use an explicit conversion function instead, such as std::to_string(), eg:
#include <iostream>
#include <string>
int main()
{
long int number = 255;
std::cout << "Value 1 : " << std::flush << std::to_string(number) << std::flush << std::endl;
number = 15155;
std::cout << "Value 2 : " << std::flush << std::to_string(number) << std::flush << std::endl;
return 0;
}
Or, you can simply let std::ostream::operator<< handle that conversion for you, eg:
#include <iostream>
int main()
{
long int number = 255;
std::cout<< "Value 1 : " << std::flush << number << std::flush << std::endl;
number = 15155;
std::cout<< "Value 2 : " << std::flush << number << std::flush << std::endl;
return 0;
}
Pointer arithmetic is the culprit.
A const char* is accepted by operator<<, but will not point to a valid memory address in your example.
If you switch on -Wall, you will see a compiler warning about that:
main.cpp: In function 'int main()':
main.cpp:6:59: warning: array subscript 255 is outside array bounds of 'const char [1]' [-Warray-bounds]
6 | std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
main.cpp:8:59: warning: array subscript 15155 is outside array bounds of 'const char [1]' [-Warray-bounds]
8 | std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
Value 1 : q
Live Demo
The code successfully compiles it but I can't understand why, for certain values of number, the program crashes and for other values it doesn't. Could someone explain the behavior of adding a long int with a char* that the compiler uses?
#include <iostream>
int main()
{
long int number=255;
std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
number=15155;
std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
return 0;
}
Test results:
Value 1 : >
Value 2 : Segmentation fault
Note: I'm not looking for a solution on how to add a string with a number.
In C++, "" is a const char[1] array, which decays into a const char* pointer to the first element of the array (in this case, the string literal's '\0' nul terminator).
Adding an integer to a pointer performs pointer arithmetic, which will advance the memory address in the pointer by the specified number of elements of the type the pointer is declared as (in this case, char).
So, in your example, ... << ("" + number) << ... is equivalent to ... << &""[number] << ..., or more generically:
const char *ptr = &""[0];
ptr = reinterpret_cast<const char*>(
reinterpret_cast<const uintptr_t>(ptr)
+ (number * sizeof(char))
);
... << ptr << ...
Which means you are going out of bounds of the array when number is any value other than 0, thus your code has undefined behavior and anything could happen when operator<< tries to dereference the invalid pointer you give it.
Unlike in many scripting languages, ("" + number) is not the correct way to convert an integer to a string in C++. You need to use an explicit conversion function instead, such as std::to_string(), eg:
#include <iostream>
#include <string>
int main()
{
long int number = 255;
std::cout << "Value 1 : " << std::flush << std::to_string(number) << std::flush << std::endl;
number = 15155;
std::cout << "Value 2 : " << std::flush << std::to_string(number) << std::flush << std::endl;
return 0;
}
Or, you can simply let std::ostream::operator<< handle that conversion for you, eg:
#include <iostream>
int main()
{
long int number = 255;
std::cout<< "Value 1 : " << std::flush << number << std::flush << std::endl;
number = 15155;
std::cout<< "Value 2 : " << std::flush << number << std::flush << std::endl;
return 0;
}
Pointer arithmetic is the culprit.
A const char* is accepted by operator<<, but will not point to a valid memory address in your example.
If you switch on -Wall, you will see a compiler warning about that:
main.cpp: In function 'int main()':
main.cpp:6:59: warning: array subscript 255 is outside array bounds of 'const char [1]' [-Warray-bounds]
6 | std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
main.cpp:8:59: warning: array subscript 15155 is outside array bounds of 'const char [1]' [-Warray-bounds]
8 | std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
Value 1 : q
Live Demo
This question already has answers here:
getting size of array from pointer c++
(6 answers)
Closed 3 years ago.
I am trying to make a function that can return the size of an array that can be different data types. I believe the expression (sizeof(z)/sizeof(*z))) returns the memory allocated to z divided by the memory size of the data type. The following code is my attempt to overload the function and return the size of the array as an integer. When I run the expression in the main function it works, but when I try to pass the array to the function I do not get the correct values and not sure what I am doing wrong. 68 / 4 = 17 which is the correct size of the array.
(1) outputs sizeof(z) and sizeof(*z) in the size function
(2) expression in main function
(3) outputs sizeof(z) in the main function
(4) outputs sizeof(*z) in the main function
#include <iostream>
using namespace std;
//
int size(int *data){
cout << sizeof(data) << ", " << sizeof(*data) << ", ";
return((sizeof(data))/(sizeof(*data)));
}
int size(char *x){return(sizeof(x)/sizeof(*x));}
int size(float *x){return(sizeof(x)/sizeof(*x));}
int size(double *x){return(sizeof(x)/sizeof(*x));}
int size(short int *x){return(sizeof(x)/sizeof(*x));}
int size(long int *x){return(sizeof(x)/sizeof(*x));}
int main(){
double x[9];
int z[17];
char k[29];
cout << "(1) Size : " << size(z) << endl;
cout << "(2) Size : " << (sizeof(z)/sizeof(*z)) << endl;
cout << "(3) Size : " << sizeof(z) << endl;
cout << "(4) Size : " << sizeof(*z) << endl;
cout << "(5) Size : " << size(z) << endl;
cout << "(6) Size : " << size(k) << endl;
return 0;
}
Terminal Output:
(1) Size : 8, 4, 2
(2) Size : 17
(3) Size : 68
(4) Size : 4
(5) Size : 8, 4, 2
(6) Size : 8
An array decays to a pointer when you pass it to another function, so sizeof(arr) will give you the actual amount of memory allocated, only in the scope of the function in which arr was declared.
There's a common mistake:
char* a // is a pointer
char b[] // is an array
when using:
char b[5]; // is an array of 5 bytes
sizeof(b); // 5
// but
char* a = b;
sizeof(a); // 8 (x64)
the last sizeof(a) is giving you the sizeof char * which is a pointer.
You can pass the name of an Array as a Pointer to the size() function, but in that function, the argument is treated as Pointer.
Hi search for a way to dump the memory layout of a class/structure/datatype with clang.
I have a simple application based on this tutorial.
I also added this function
bool VisitFieldDecl(FieldDecl *F)
{
F->dump();
std::cerr << F->getQualifiedNameAsString() << " " << F->getBitWidthValue(*Context) << " " << std::endl;
F->dump() ;
std::cerr << "-----------------------------------------" << std::endl;
return true;
}
Unfortunately getBitWidthValue also returns zero for my types.
I need the complete memory-layout recursively for each class and all nested types. Including sizes/offsets.
Maybe the AST is the wrong place, and i need a other hook to start?
One way would be to use the "AST Record Layout" of a given const clang::CXXRecordDecl* decl in llvm/clang-3.4:
const clang::ASTRecordLayout &typeLayout(decl->getASTContext().getASTRecordLayout(decl));
std::cout << "record '" << decl->getQualifiedNameAsString() << "' with " << typeLayout.getSize().getQuantity() << "bytes\n";
for(clang::RecordDecl::field_iterator fit = decl->field_begin(); fit != decl->field_end(); fit++) {
const clang::QualType qualType = fit->getType().getLocalUnqualifiedType().getCanonicalType();
size_t fieldOffset = typeLayout.getFieldOffset(fit->getFieldIndex());
std::cout << "member '" << qualType.getAsString() << "' with " << fieldOffset/8 << " bytes offset\n";
}
no warranties: Code copied together, not tested as typed here -- but should work... (tm)
Example:
struct EXAMPLE
{
char a;
int b;
long c;
long long d;
float e;
double f;
};
Output:
record 'EXAMPLE' with 40 bytes
member 'char' with 0 bytes offset
member 'int' with 4 bytes offset
member 'long' with 8 bytes offset
member 'long long' with 16 bytes offset
member 'float' with 24 bytes offset
member 'double' with 32 bytes offset
for more see:
https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html
https://clang.llvm.org/doxygen/classclang_1_1ASTRecordLayout.html
EDIT:
Though badly formatted this Question had a nice catch.So, I am editing this to retain this in a better format for future visitors who stumble across this question.
In the code sample below can someone please explain Why is the size of class different than expected after memcpy? What is the reason?
Here is the online demo on Ideone.
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
using namespace std;
class A
{
public:
int a;
virtual void f1() { cout <<"inside a::f1\n"; }
A() { a = 1; }
};
class B
{
public:
int b;
virtual void f2() { cout <<"inside b::f2\n"; }
virtual void f5() { cout <<"inside b::f5\n"; }
B() { b = 2; }
};
class C : public A, public B
{
public:
int c;
void f1() { cout <<"inside c::f1\n"; }
void f2() { cout <<"inside c::f2\n"; }
virtual void f3() { cout <<"inside c::f3\n"; }
virtual void f4() { cout <<"inside c::f4\n"; }
C() { c = 3; }
};
int fun()
{
int a = 1;
return a * 2;
}
int main()
{
C c;
C c2;
int (*g)() = &fun;
void (A::*g1)() = &A::f1;
void (C::*g2)();
g2 = &C::f1;
(c.*g2)();
printf("%p\n",g2);
cout << sizeof(g2) << endl;
g2 = &C::f2;
(c.*g2)();
printf("%p\n", g2);
// Why is the output 1 here in g++ or visual C++?
cout << g2;
// Why is the sizeof returning 8? Please explain.
cout << sizeof(g2) << endl;
g2 = &C::f1;
std::vector<unsigned char> a_vec(sizeof(g2));
memcpy(&a_vec[0], &g2, sizeof(g2));
for(size_t i = 0; i < sizeof(g2); ++i)
{
cout << hex << static_cast<unsigned>(a_vec[i]) << " ";
}
cout << endl;
g2 = &C::f2;
std::vector<unsigned char> a_vec1(sizeof(g2));
memcpy(&a_vec1[0], &g2, sizeof(g2));
for(size_t i = 0; i < sizeof(g2); ++i)
{
cout << hex << static_cast<unsigned>(a_vec1[i]) << " ";
}
cout << endl;
cout << sizeof(g) <<endl;
cout << sizeof(g1) <<endl;
cout << sizeof(g2) <<endl;
// Why is sizeof(C) printing 14 and not 20 in visual C++?
// If yes why is this so ?
cout << sizeof(C) << endl;
cout << sizeof(c2) << endl;
cout << (&c) << endl;
cout << c.a << endl;
cout << c.b << endl;
cout << c.c << endl;
return 0;
}
From the above code sample the Output I get is:
inside c::f1
0x1
8
inside c::f2
0x5
18
1 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0
4
8
8
14
14
0xbffe375c
1
2
3
Following are my Questions:
Why is the output 1 here in g++ or visual C++?
cout << g2;
Why is the sizeof returning 8? Please explain.
cout << sizeof(g2) << endl;
Why is sizeof(C) printing 14 and not 20 in visual C++? If yes why is this so?
cout << sizeof(C) << endl;
Why is the sizeof returning 8. Please explain?
cout <<sizeof(g2)<<endl;
returns 8 because g2 is a pointer and size of an pointer on your enviornment is 8.
Why is the output 1 here in g++ or visual C++?
cout << g2;
The << operator does not have an overloaded version which accepts a pointer. So the pointer gets converted to a bool type, with a value 1, and cout prints it.
The C++ Standard allows this:
C++03 Standard 4.12 Boolean conversions
1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool.
Why is sizeof(C) printing 14 and not 20 in visual C++.
cout<<sizeof(C)<<endl;
It displays the size of C correctly just in hexadecimal(14 in hex == 20 in decimal). This is because you used the hex I/O manippulator to print an address before.
cout<<dec<<sizeof(C)<<endl;
will set the I/O manipulator to decimal mode again and it will output 20 as you expect.
A word about printf and type safety:
printf is not type safe.When using printf it is the users responsibility to pass the proper formart descriptor and data type to it. If there is a mismatch then an Undefined Behavior will occur. An Undefined behavior means that the program might crash or show any weird behavior.
printf( "%p\n", g2 );
Is an example of Undefined Behavior, there is a mismatch in the format descriptor and the data type. Note that the compiler does complain about this and you should always look out and check such warnings emitted by the compiler.
warning: format ‘%p’ expects type ‘void*’, but argument 2 has type ‘void (C::*)()’
The results of sizeof for a given type never change. (At least for a
conforming C++ program. g++, I believe, supports VLAs in C++, as an
extension, and the sizeof an object containing a VLA might change.)
With regards to your explicit questions:
printf( "%p\n", g2 );
is undefined behavior. You're passing a pointer to member to an output
formatter which requires a void*. (g++ will warn about this, I
believe, at least with certain options.) You might get just about
anything (including a program crash). Pointers to members are not
void*, and can't be converted to void*.
cout << g2;
I can't believe that this compiles.
cout << sizeof(g2) << endl;
sizeof(g2) returns 8 because this is the size of a pointer to member
on your system.
cout << sizeof(C) << endl;
Prints 14 because this is the size in hexadecimal of an object of type
C on your system. In other words, sizeof(C) is 20. Since you've
set output for hex, and never reset it, the output is hexadecimal.