[QUOTE=Gbps;23293933]It's really just a shortcut of pointers.[/QUOTE]
It's really not, though. They have completely different rules and syntax, and different purpose. The only thing they really have in common is that before references, pointers were usually used to do the job references do today. A pointer is a crude tool, and best left to edge cases where another construct simply won't do (like dealing with low-level arrays, or dynamic cases where the same pointer keeps changing value).
[QUOTE=alex1996arm;23293538]now where can i find some information on how to use a reference?[/QUOTE]
[code]
#include <iostream>
void foo(int &n) { // takes an int reference
n = 42;
}
int main(int argc, char *argv[]) {
int x = 1;
foo(x); // passes x by reference
std::cout << x << std::endl;
return 0;
}
[/code]
[QUOTE=jA_cOp;23297980]It's really not, though. They have completely different rules and syntax, and different purpose. The only thing they really have in common is that before references, pointers were usually used to do the job references do today. A pointer is a crude tool, and best left to edge cases where another construct simply won't do (like dealing with low-level arrays, or dynamic cases where the same pointer keeps changing value).[/QUOTE]
It's a shortcut of pointers used in basic function level input/output. I wasn't implying that it was like "pointers 2.0" or something.
No, it works differently. It really does.
If you wanna go down that road you could just as well say that any variable is quite probably actually just a shortcut to pointers, since you won't be able to fit all within the processor registers in a mildly larger program.
But while a pointer would require the variable to not just be inside a register (unless the compiler does some optimizations if it finds out that you really just use it as a reference), that requirement would not exist for a reference.
Some uses of references may be implemented similarly to pointers in the compiled machine code, but that's an implementation detail of the compiler, not something you can assume or rely on. It's perfectly valid for the compiler to implement references some other way.
For example, if you do
[code]
int a = 42;
int &b = a;
[/code]
there's no need to take the address of anything. The compiler can just treat both names as synonyms for the same value, and that value can be stored in a register and not even [i]have[/i] an address, as ZeekyHBomb said.
Oh, I see now. I guess I've been spending too much time with compiled machine code to recognize the difference.
Why the boxes? I didn't understand what references were because the references I've seen are with a particular engine I like to RE has a compiler that treats references more like pointers than copies.
I have finally learned how pointers work in C (haven't gotten around to learning C++ yet) and there's something disgustingly awesome about them.
I love doing stuff like casting an array of chars to an integer with pointers. It feels like you're cheating.
I see that people have already discussed this to death in here, but here's how I think about '*': * tells a pointer to point. So if you write
[code]char * ptr;[/code]
because of *, ptr says "I'm not a char, but I'm pointing at a char." Similarly, when you write
[code]*ptr = 'A';[/code]
ptr is saying "Don't set me equal to 'A', set whatever I point to equal to 'A'." I know it's a silly, childish way to look at it but it really helped when I was starting out.
I think that's nifty, myself.
[QUOTE=Larikang;23345341]
I love doing stuff like casting an array of chars to an integer with pointers. It feels like you're cheating.[/QUOTE]
Then you find out that it's actually not the same integer when you compile and run the program on a platform with different endianness.
Although I suppose you could cast a char[4] to int to check endianness and solve this problem.
[cpp]
char test[] = { 0, 0, 0, 255 }
int testInt = *( (int *) test );
bool smallEndian = false;
if ( testInt == 255 ) smallEndian = true;
[/cpp]
Woop.
[QUOTE=esalaka;23350271]Then you find out that it's actually not the same integer when you compile and run the program on a platform with different endianness.
Although I suppose you could cast a char[4] to int to check endianness and solve this problem.
[cpp]
char test[] = { 0, 0, 0, 255 }
int testInt = *( (int *) test );
bool smallEndian = false;
if ( testInt == 255 ) smallEndian = true;
[/cpp]
Woop.[/QUOTE]
int is not defined as 4 bytes.
Is char defined as 1 byte?
[cpp]// will fail if sizeof(int) == sizeof(char) and small endian machine
unsigned char test[sizeof(int) / sizeof(char)] = { 0 };
test[sizeof(test) / sizeof(char) - 1] = 1;
bool bigEndian = *(reinterpret_cast<int*>(test)) == 1;[/cpp]
sizeof(char) is defined as 1 (which can be 1 byte), else I'm pretty sure it only defines this:
[cpp]
sizeof(char) < sizeof(short) < sizeof(int) < sizeof(long long int)
[/cpp]
(but 'long long int' is C99 and C++0x specific)
[url]http://stackoverflow.com/questions/1240121/sizeofint-sizeoflong-sizeoflong-long-always-true[/url]
So you could omit all the sizeof(char) in my code. sizeof(int) == sizeof(char) is possible though.
[QUOTE=jA_cOp;23360748]sizeof(char) is defined as 1 (which [b]is[/b] 1 byte)[/QUOTE]
Fixed that for you.
[QUOTE=Larikang;23345341]I have finally learned how pointers work in C (haven't gotten around to learning C++ yet) and there's something disgustingly awesome about them.
I love doing stuff like casting an array of chars to an integer with pointers. It feels like you're cheating.[/QUOTE]
You would really have fun with ASM then. There are no intrinsic types, just data and addresses.
[QUOTE=jA_cOp;23360102]int is not defined as 4 bytes.[/QUOTE]
Well, uh, damn, I guess I thought he's using a 32-bit Windows system where it is. (Also it should've been UNSIGNED int, goddamn my errors D:)
Anyway, you could just replace that with uint32_t and all would be well and good, rite?
[QUOTE=esalaka;23388357]
Anyway, you could just replace that with uint32_t and all would be well and good, rite?[/QUOTE]
Yeah, you should. If you made a bunch of overloads like:
[cpp]
void sendOverNetwork(uint8_t i);
void sendOverNetwork(uint16_t i);
void sendOverNetwork(uint32_t i);
...
[/cpp]
Then called:
[cpp]
unsigned int i = 1234;
sendOverNetwork(i);
[/cpp]
It would choose the correct size at compile-time, anyway.
[QUOTE=jA_cOp;23388649]Yeah, you should. If you made a bunch of overloads like:
[cpp]
void sendOverNetwork(uint8_t i);
void sendOverNetwork(uint16_t i);
void sendOverNetwork(uint32_t i);
...
[/cpp]
Then called:
[cpp]
unsigned int i = 1234;
sendOverNetwork(i);
[/cpp]
It would choose the correct size at compile-time, anyway.[/QUOTE]
Wait, what, are you implying that htonl and the likes are implemented like that little piece of code of mine? o_O
[QUOTE=esalaka;23389868]Wait, what, are you implying that htonl and the likes are implemented like that little piece of code of mine? o_O[/QUOTE]
No, I doubt it. But those functions don't actually [I]check[/I] the endianness of a value, they just convert from one to the other.
edit:
In modern C++, you can do this with some brief templated code anyway. gparent and I made this a while back:
[cpp]
#ifndef ENDIANNESS_HPP
#define ENDIANNESS_HPP
#include <algorithm>
template<typename T>
T switch_endianness(T);
template<typename T, int i>
struct Endianness
{
static void swap(char* array)
{
std::swap(array[(sizeof(T) - i)], array[i-1]);
Endianness<T, i-1>::swap(array);
}
};
template<typename T>
struct Endianness<T, 0>
{
static void swap(char* array){}
};
template<typename T>
T switch_endianness(T i)
{
char* array = reinterpret_cast<char*>(&i);
Endianness<T, sizeof(T)/2>::swap(array);
return i;
}
#endif
[/cpp]
Used like:
[cpp]
uint16_t a = 0xFF00;
a = switch_endianness(a);
assert(a == 0x00FF);
[/cpp]
[QUOTE=jA_cOp;23389962]No, I doubt it. But those functions don't actually [I]check[/I] the endianness of a value, they just convert from one to the other.[/QUOTE]
They probably have a constant somewhere that tells the functions if the current system is small-endian or big-endian :P
Sorry, you need to Log In to post a reply to this thread.