Table of contents
Pointer
(2023-11-09) Review:
A pointer variable and a regular variable are 2 ways of indexing memory.
-
A pointer variable stores the address of the start byte of a variable. And its type indicates how many bytes the complete data takes.
-
Pointer variable is an address, a unsigned integer, whose size depends on system architecture (32-/64-bit addr). While a variable represents the whole data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15// "pointer.c" #include <stdio.h> int main(){ int a = 1; int* p = &a; printf("a = %d \n", a); printf("p = %p \n", p); printf("address of a = %p \n", &a); printf("#bytes of a = %ld \n", sizeof(a)); printf("#bytes of p = %ld \n", sizeof(p)); int b[2][2] = {1,2,3,4}, *ptr_b = &b[2][2]; printf("#bytes of b = %ld \n", sizeof(b)); printf("#bytes of ptr_b = %ld \n", sizeof(ptr_b)); }Build
gcc pointer.c -o pointerand run./pointer.Output:
1 2 3 4 5 6 7a = 1 p = 0x7ffe45d7c88c address of a = 0x7ffe45d7c88c #bytes of a = 4 #bytes of p = 8 #bytes of b = 16 #bytes of ptr_b = 8 -
The
*p(dereferenced p) andiare equivalent at all time.1 2 3int i = 1; int* p = &i; bool cf_res = (*p == i); // 1
-
(2023-11-11)
char*indicates the direction: from pointer*tochar. Similarly,char**means from a pointer*to another pointer*, then tochar. -
void* ptr = 0. Address 0 isNULLornullptr.voidmeans dismissing the type of the data it points to.
Reference
Note: C doesn’t have reference. SO
A reference variable is an alias. Compared to pointer, it’s an already dereferenced address.
|
|
-
Declaration and initialization must be performed at the same time.
1 2 3 4 5int& ref; // incorrect ref = i; int* ptr; ptr = &i; // ok -
Reference variable cannot be reassigned.
1 2 3 4 5 6int i =0, j =1; int& ref1 = i; int& ref1 = j; // error: redeclaration of ‘int& ref1’ int& ref2 = ref1; // ok std::cout << ref2 << std::endl; // 0 -
Reference shares the same memory as the variable, not occupying another memory.
-
Pass reference into function to modify the source data directly. Pointer needs deferencing to access the data.
-
Python only has reference without pointer.
1 2 3 4 5 6 7 8 9 10 11#include<iostream> int main(){ int i = 0; std::cout << &i << std::endl; // 0x7ffd18889e74 int* ptr = &i; std::cout << &ptr << std::endl; // 0x7ffd18889e78 int& ref = i; std::cout << &ref << std::endl; // 0x7ffd18889e74 } -
-
Use reference for function parameters and return types.
Use references when you can, and pointers when you have to. C++ FAQ
-
Iteration:
1 2 3 4 5 6 7 8 9 10 11#include <iostream> #include <vector> int main(){ vector<int> myVec; myVec = {1,2,3,4,5}; // for (int i:myVec) // will copy item to i for (int& i : myVec) // use reference to avoid copy data std::cout << i << std::endl; } -
Pass reference to function to avoid copying:
1 2 3 4 5 6 7 8 9void Function(const std::vector<int>& myVec){ for (int i : myVec) std::cout << i <<std::endl; } int main(){ std::vector<int> myVec={1,2,3}; Function(myVec); }
-
-
A pointer to a class/struct uses
->to access its members, whereas a reference uses.(Same as python.) What are the differences between a pointer variable and a reference variable? - SO
Ref:
Raw Array
(2023-11-11)
-
The variable name
exampleArrayis an address of the starting byte, so it’s a pointer.1f = -
Array is a row of contiguous memory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55#include <iostream> int main(){ // Create an array on stack, which // will be destoryed when getting out of the scope int exampleArray[4]; for (int i=0; i<5; i++) exampleArray[i] = i; cout << exampleArray << " is the address of the array" << endl; cout << &(exampleArray[0]) << " is the address of the first element" << endl; cout << *exampleArray << " is the first element by dereferencing the pointer" << endl; // Get the 3rd elements can do arithmatic on pointer, // where the size of the type will be multiplied automatically. cout << *(exampleArray + 2) << " is the 3rd element"<< endl; // If access the 2nd elements by calculating in bytes, // cast integer pointer to char pointer with is 1-byte type. // After locating the address, cast back to integer pointer for assigning a integer value. *(int*)((char*)exampleArray + 8) = 30; cout << exampleArray[2] << " is the modified 3rd element" << endl; cout << sizeof(exampleArray) << " bytes taken by the entire array"<< endl; // For array created on stack, the number of elements can be known because stack pointer contains offset: int num_elements = sizeof(exampleArray) / sizeof(int); cout << num_elements << " elements in the array on stack" << endl; // Create an array on heap with the `new` keyword, // This array is the same as exampleArray, except for its lifetime that lasts until calling `delete[] arrayname`. // So if an array created inside function needs to be returned, it must be created on heap int* exampleArray_heap = new int[4]; // is a pointer (address 0x55555556b2c0) to heap, not the 1st element 0, for (int i=0; i<4; i++) exampleArray_heap[i] = i; // Read the "address" from memory in bytes std::cout << std::hex << *(long long*)&exampleArray_heap << std::endl; cout << &exampleArray_heap << " stores the 8-byte address (the pointer) to the array" << endl; cout << exampleArray_heap << " is the address (pointer) to the array on heap" << endl; // cast type to integer pointer cout << *(exampleArray_heap+0) << " is the first element in the array" << endl; // one more jump will reduce performance // exampleArray_heap is a pointer of pointer (memory indirection). An 32-bit address taking 4 bytes cout << sizeof(exampleArray_heap) << " bytes for the pointer of the array on heap" << endl; // delete[] exampleArray_heap; // If array is not created on stack, or only has the pointer to an array, // the number of elements can't be computed as sizeof(array)/sizeof(int). So it must be maintained. static const int exampleSize = 5; // must be known at compile-time int myArray[exampleSize]; } -
Create an array on heap.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15class Entity{ public: int* exampleArray_obj = new int[4]; Entity(){ // construction function for (int i=0; i<4; i++) exampleArray_obj[i] = i; } }; int main(){ Entity e; cout << e.exampleArray_obj << " is the address (pointer) to array" << endl; cout << *(e.exampleArray_obj) << " is the 1st element of array" << endl; // 0 } -
std::arrayhas.size().1 2 3 4 5 6 7 8 9#include <iostream> #include <array> int main(){ std::array<int, 4> myArray; for(int i=0; i<myArray.size(); i++) myArray[i] = i; }
Ref:
Pointer Alignment
(2023-11-14)
(Unsure about my naming for this.)
Because the algorithm specifies processing 128 data at a time, i.e., the factor alignment = 128.
Thus, each time 128*sizeof(dtype) memory will be accessed.
Therefore, the pointers to data should all be multiples of 128.
The way to round a number to a multiple of 128 is setting its last 8 bits to 1000_0000 (128).
-
The type of pointer affects its arithmetic:
1 2 3 4 5 6 7 8 9 10 11#include <iostream> int main(){ // int-type pointer: int* chunk = nullptr; // 8-byte address: 0 0 0 0 0 0 0 0 int* ptr = chunk + 127; // 0 + 127*sizeof(int) = 508 = 0x1fc std::cout << ptr << std::endl; // 0x1fc // char-type pointer: char* ptr2 = (char*) chunk + 127; // 0 + 127*sizeof(char) = 127 = 0x7f std::cout << static_cast<void*>(ptr2) << std::endl; // 0x7f } -
Convert a pointer to an integer: SO
1 2char* chunk = nullptr; uint var = reinterpret_cast<std::uintptr_t>(chunk); // ok -
Ensure offset a multiple of 128:
If the currect pointer
chunkis not a multiple of 128, add another 127, and then truncate the last 8 bits to1000_000to make it a multiple of 128.1 2 3 4 5 6int main(){ char* chunk = (char*)130; std::size_t alignment = 128; // uint // 130 + 127 & ~127 = 256 std::size_t offset = (reinterpret_cast<std::uintptr_t>(chunk) + alignment - 1) & ~(alignment - 1); // uint }Bitwise operation:
1 2 3 4 5chunk: 0000_0000_1000_0010 alignment-1: 0000_0000_0111_1111 ~(alignment-1): 1111_1111_1000_0000 chunk + (alignment-1): 0000_0001_0000_0001 (257) (257)&~(127) = 256: 0000 0001 0000 0000Code from 3DGS
Possible related articles:
size_t
(2024-01-24)
-
size_tis the unsigned integer type. For example, if it’s 8 bytes (64-bitunsigned long), its value ranges in [0, 2⁶⁴-1]. In other words, if a number is larger than 2⁶⁴-1, it can’t be declared as thesize_ttype. -
Usage: Given a variable that stores the number of elements of an array, or number of bytes of an object, it can be set as the
size_ttype, as the name indicated thatsize_tis used for representing a “size”.
|
|
mrefers tounsigned longinteger. The returned strings are defined differently across various compilers. So, the correct meaning should be found in the implementation. Strange output of std::typeid::name() - SO
Do not use typeid
The returned string is not consistent; Need to check the documents.
Ref: typeid(xxxx).name() “m” returned? - C++ Forum
Reserve Memory
(2024-01-26)
-
Pad the
lastCountvalue to a multiple of thealignment128, and then allocate the followingcountbytes, which is the number of elements of the target data pointed bydataPtr:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25// "reserve_memory.cpp" #include <torch/torch.h> template <typename T> // T can be int, float..., deduced when compiling void accum(char*& lastCount, T*& dataPtr, size_t count, size_t alignment) { // Decimal arithmetic size_t offset = (reinterpret_cast<std::uintptr_t>(lastCount) + alignment-1) & ~(alignment-1); // Update the pointer to the data to be filled dataPtr = reinterpret_cast<T*>(offset); // Accumulate the number of bytes of the data lastCount = reinterpret_cast<char*>(dataPtr+count); } int main(){ char* size = nullptr; // Count from 0x0 float* depth; // sizeof(float) = 4 bytes float* color; accum(size, depth, 100, 128); // 0 + 100*4 = 400 bytes = 0x190 bytes printf("%p \n", size); // 0x190 accum(size, color, 100*3, 128); // 512 + 300*4= 1712 bytes = 0x6b0 bytes printf("%p \n", size); // 0x6b0 return 0; }-
char*& size = nullptr: the variablesizeis an alias of thenullptr, sharing the same memory.Such that the pointer (
lastCountanddataPtr) is changed directly.
-
-
Compilation. Ref: Troubles while compiling C++ program with PyTorch, HElib and OpenCV - SO
1 2 3 4 5 6 7 8g++ -g -std=c++17 \ -I/usr/local/libtorch/include \ -I/usr/local/libtorch/include/torch/csrc/api/include \ -I/usr/local/libtorch/include/torch \ -L/usr/local/libtorch/lib \ -Wl,-rpath,/usr/local/libtorch/lib \ reserve_memory.cpp \ -ltorch -ltorch_cpu -lc10 # Order matters: After .cpp file-
doubt: If I add
-O2option, the libraries-ltorch -ltorch_cpu -lc10can be omitted. Don’t know why. With-O2optimization, debugging will become difficult. -
The original anwser:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17g++ -g -O2 -std=c++17 \ -pthread \ -march=native \ -I/home/lulu/helib_install/helib_pack/include \ -I/usr/include/opencv4 \ -I/home/lulu/libtorch/include \ -I/home/lulu/libtorch/include/torch/csrc/api/include \ -I/home/lulu/libtorch/include/torch \ -L/home/lulu/helib_install/helib_pack/lib \ -L/usr/include/opencv4 \ -L/home/lulu/libtorch/lib \ -Wl,-rpath,/home/lulu/libtorch/lib \ prova.cpp \ -lopencv_core -lopencv_highgui -lopencv_imgcodecs \ -lhelib -lntl -lgmp -lm \ -ltorch -ltorch_cpu -lc10 \ -o prova
-