| Generic C++ questions |
|
Forum Index - Hobbies - Computers & Technology - Generic C++ questions |
|
Pages: 1 2  |
|
|
|
| Posted on 2011-08-19 10:34:45 AM |
Link | Quote |
|
(Original title: Getting a string from a block of memory)
Actually a wstring but whatever.
Suppose I upload a file to a chunk of memory. I know that at a certain point in this file is a wstring that I need to retrieve. Unfortunately something like "&wstr = memblock + 0x80" doesn't seem to work. Is there any obvious way of making a wstring use content that already exists in memory, or am I going to have to copy each character byte by byte to a wstring somewhere else in memory?
|
| Last edited on 2011-08-24 07:46:07 PM by Kipernal. |
|
| Posted on 2011-08-19 12:47:37 PM |
Link | Quote |
|
Do you want to explicitly work with the memory block or do you just need the string?
If you just want the string, try
Codewstring wstr((wchar_t*)(memblock+0x80));
However, if you want to work with the memory itself in a wstring format, I'm afraid you can't. You can, however, work with it as a wchar_t pointer/array, which is essentially the same as wstring, except you do not have the ability to use the wstring functions like append, erase, find, etc. If this is what you want, then just do
Codewchar_t *wstr = (wchar_t*)(memblock+0x80);
|
|
| Posted on 2011-08-19 01:44:06 PM |
Link | Quote |
|
Originally posted by spel werdz riteDo you want to explicitly work with the memory block or do you just need the string?
If you just want the string, try
Codewstring wstr((wchar_t*)(memblock+0x80));
That's exactly it. Thank you!
...while I'm here, though, I have one other question. The file is indexed with chars (since most values are just a single byte). Suppose, however, I wanted to read a short from it. Is there any better way other than "short s = memblock[i]*0x100+memblock[i]"?
|
| Last edited on 2011-08-19 01:44:26 PM by Kipernal. |
|
| Posted on 2011-08-19 02:02:23 PM |
Link | Quote |
|
You're missing a +1 in one of those [i]s.
Either way, try this:
short s = *(short*)(memblock+i);
Edit: Stupid html filter...
|
| Last edited on 2011-08-19 02:02:42 PM by Alcaro. |
|
| Posted on 2011-08-19 02:43:08 PM |
Link | Quote |
|
Originally posted by AlcaroYou're missing a +1 in one of those [i]s.
You'd think I would have caught that when I replaced "int s" with "short s"...
Originally posted by AlcaroEither way, try this:
short s = *(short*)(memblock+i);
Ah, thanks. That brings up one final issue, though: since I'm building this on a machine that uses little-endian, is there any way to protect against big-endian machines other than rewriting the code for those processors?
|
|
| Posted on 2011-08-19 03:26:21 PM |
Link | Quote |
|
Code#if defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64)
#define ARCH_LSB
#elif defined(__powerpc__) || defined(_M_PPC) || defined(__BIG_ENDIAN__)
#define ARCH_MSB
#endif
This + #ifdef + #error should solve it.
Edit: If that's not good enough, short s = memblock[i]*0x100+memblock[i+1] might solve it.
Edit 2: On big endian platforms, there's a chance the source data is also big endian. It may be wise to try not doing anything at all.
|
| Last edited on 2011-08-19 03:29:10 PM by Alcaro. |
|
| Posted on 2011-08-24 08:07:44 PM |
Link | Quote |
|
I was going to make a new topic for this question, but if I did that for every simple thing I'd ask I'd begin to clog up the forum.
Okay, so if this works fine:
Why don't these work?
Codeint x = 5;
int y = 5;
int * n = new int[x][y];
Codeint * n = new int[5][5];
Arrays seem to be kind of weird different in C++ so maybe it's just something I'm misunderstanding.
|
| Last edited on 2011-08-24 08:08:52 PM by Kipernal. |
|
| Posted on 2011-08-24 08:41:53 PM |
Link | Quote |
|
Yeah, you can't just define a multidimensional dynamic array like that. Try this:
Codeint ** n;
n = new int*[x];
for(int h = 0; h < rows; h++)
a[h] = new int[y];
|
|
| Posted on 2011-08-26 03:23:15 PM |
Link | Quote |
|
Originally posted by HuFlungDuYeah, you can't just define a multidimensional dynamic array like that. Try this:
Codeint ** n;
n = new int*[x];
for(int h = 0; h < rows; h++)
a[h] = new int[y];
I won't lie, that seems rather needlessly complex (the fact that the compiler can't do it itself I mean, not your code). Thank you.
|
|
| Posted on 2011-08-26 05:02:00 PM |
Link | Quote |
|
Yeah, I'm not a super fan of C++, it tends to be too cryptic for my tastes, but it does have it's advantages.
That's not even actually a multi dimensional array to be honest, it's just an array of arrays (I think they end up being more or less the same thing though).
|
|
| Posted on 2011-08-26 06:52:07 PM |
Link | Quote |
|
Originally posted by HuFlungDuYeah, I'm not a super fan of C++, it tends to be too cryptic for my tastes, but it does have it's advantages.
That's not even actually a multi dimensional array to be honest, it's just an array of arrays (I think they end up being more or less the same thing though).
Well you could always allocate a block of memory yourself [m*n] and just access it that way. Then again people rave about how you should use vectors over arrays anyways. Vectors are quite nice, though I am not so fond of the native ones and thus wrong my own.
|
|
| Posted on 2011-08-28 11:00:05 PM |
Link | Quote |
|
Okay, another question: say I wanted to get every byte of data from a wstring as a char (the one-byte data type, not a character...not that it really matters, I suppose...). I've tried various things like
Codefor (int i = 0; i < wstr.length()*2; i++)//wstr is the string to work with.
{
char * ptr = (char*)(&wstr) + 8;
char byte = *(char*)ptr; //Get the byte of the string.
ptr++; //I'm not doing anything with it here since it's only an example.
}
and
Codefor (int i = 0; i < wstr.length()*2; i++)
{
void * ptr = (&wstr) + 8;
char byte = *(char*)ptr;
((char*&)ptr)++;
}
but obviously none of them work. Could anyone lend a hand here?
Also, maybe it's just me, but I really wish C++ would let the user do the pointer math themselves instead; I feel like I'm fighting the compiler here to get what I want.
|
| Last edited on 2011-08-29 01:37:49 AM by Kipernal. |
|
| Posted on 2011-08-29 01:02:12 AM |
Link | Quote |
|
I'm missing a bunch of data types here. Is wstr of type wchar_t*? If yes, what is that & and that +8 doing there? If no, then what is it?
and why do you want UTF16 anyways? UTF8 is much better.
|
|
| Posted on 2011-08-29 01:36:58 AM |
Link | Quote |
|
Originally posted by AlcaroI'm missing a bunch of data types here. Is wstr of type wchar_t*? If yes, what is that & and that +8 doing there? If no, then what is it?
and why do you want UTF16 anyways? UTF8 is much better.
wstr is just the name of the wide string...sorry for not pointing that out. The +8 is there because for some reason wide strings seem to start 8 bytes ahead of where their address points (which also explains the &)...I don't know why, but they always seem to be padded at the front by 0x00000000CCCCCCCC.
And I'm not using UTF-8 because...I didn't know I wasn't using it. Though a better answer is that Unicode support is already rather hit-or-miss and I don't want to further push my luck.
|
|
| Posted on 2011-08-29 05:29:26 AM |
Link | Quote |
|
Codeconst wchar_t *wc = wstr.c_str();
int l = wstr.length();
char* c = (char*)malloc(l + 1);
for (int i = 0; i < l; i++)
c[ i] = (char)wc[ i];
c[l] = 0;
The 8-byte padding you are experiencing is the rest of the wstring data. You seem to not realize that there are fundamental differences between wchar_t* and wstring. You see, wstring is a class which contains a wchar_t array and some related functions (such as length and padding etc.) whereas wchar_t* is just a data array and does not contain any added info. You can get the wchar_t array by calling the wstr.c_str() method. The data type has to be const wchar_t* though. Hopefully that makes sense.
|
|
| Posted on 2011-08-29 06:24:58 PM |
Link | Quote |
|
Originally posted by spel werdz riteThe 8-byte padding you are experiencing is the rest of the wstring data. You seem to not realize that there are fundamental differences between wchar_t* and wstring. You see, wstring is a class which contains a wchar_t array and some related functions (such as length and padding etc.) whereas wchar_t* is just a data array and does not contain any added info. You can get the wchar_t array by calling the wstr.c_str() method. The data type has to be const wchar_t* though. Hopefully that makes sense.
It does (and I was aware that a string and a character array are different, but since the data that preceded the string looked like garbage, I was confused), but the way I figure it, if the data is already there in memory (i.e. somewhere in memory is a block of data that contains a string of wchar_ts), then why can't I just access it from there instead of relying on a function that eats up time (not much time, maybe, but optimization is key).
Essentially, the data is already in memory somewhere, so I don't want to be redundant and copy it elsewhere just so I can read it.
|
|
| Posted on 2011-08-30 12:45:17 AM |
Link | Quote |
|
In my headers, that function looks like this:
Code const _Elem *__CLR_OR_THIS_CALL c_str() const
{ // return pointer to null-terminated nonmutable array
return (_Myptr());
}
Code const _Elem *__CLR_OR_THIS_CALL _Myptr() const
{ // determine current pointer to buffer for nonmutable string
return (_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf);
}
Most compilers optimize this away and puts the function bodies in your code (this is called "inlining"). The data isn't copied, only the pointer to it (which takes eight bytes) is.
The reason why pointer magic is a bad idea is this object has two pointers, and it looks like it switches between them depending on the string length. This means that your code may work for wstring str=L"Lorem ipsum";, but it'll break for wstring str=L"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";. However, the C++ specification guarantees that c_str() will give the correct response no matter what the string length is.
|
|
| Posted on 2011-08-30 01:00:20 PM |
Link | Quote |
|
Originally posted by AlcaroThe data isn't copied, only the pointer to it (which takes eight bytes) is. ... The reason why pointer magic is a bad idea is this object has two pointers, and it looks like it switches between them depending on the string length.
Okay, that makes sense.
New question (and I hope by this point I'm not being annoying or anything...):
Suppose I have two classes: classA and classB. classA has a function that modifies a variable in an instance of classB. My question is: how do I make these two classes aware of each other? classA requires that it be compiled before classB, and classB requires that it be compiled before classA. And I can't just #include the classes' header files since classA.h would #include classB.h which would #include classA.h, and I'm assuming that there's some sort of safeguard against infinite recursion since it doesn't end up working correctly.
For the sake of simplicity, here's what the files look like:
main.cpp:
Code#include "stdafx.h"
#include "classA.h"
#include "classB.h"
int _tmain(int argc, _TCHAR* argv[])
{
classB objB;
return 0;
}
classA.h:
Codeclass classA
{
public:
void doStuff(classB* objB);
classA(void);
~classA(void);
};
classB.h:
Codeclass classB
{
public:
int var;
classB(void);
~classB(void);
};
classA.cpp:
Code#include "StdAfx.h"
#include "classA.h"
classA::classA(void)
{
}
void classA::doStuff(classB* objB)
{
&objB.var = 0;
}
classA::~classA(void)
{
}
classB.cpp:
Code#include "StdAfx.h"
#include "classB.h"
classB::classB(void)
{
classA objA;
objA.doStuff(this);
}
classB::~classB(void)
{
}
Also, am I free to assume that that is the proper way to use the "this" pointer?
|
|
| Posted on 2011-08-30 01:38:59 PM |
Link | Quote |
|
Your usage of this seems correct to me, but &objB.var = 0; is wrong. The correct method is objB->var = 0;.
Solution to class orders:
Codeclass ClassA;
class ClassB;
//The compiler now knows that ClassA and ClassB are classes. Pointers and references to to them may be used
//freely, but their contents aren't known, and may therefore not be accessed right now.
class ClassA {
public:
ClassB * myB;
void modify(ClassB * B);
};
class ClassB {
public:
ClassA * myA;
void modify(ClassA * A);
};
//At this point, the compiler knows what ClassA and ClassB contains. Code to modify them is now permitted.
void ClassA::modify(ClassB * B)
{
myB=B;
}
void ClassB::modify(ClassA * A)
{
myA=A;
}
Another solution could be something like this, but for circular dependencies like my example, it's better to define both in the same file (or at least the same header file) in 99% of the cases. If they depend on each other this much, they're closely related to each other, and both should probably be made fully accessible if one of them is.
I don't know what's best for your current code. I'll let you decide that.
Guess: This is some sort of homework, and either your teacher is bad or you want to move faster than the rest of the class.
|
| Last edited on 2011-12-11 02:28:43 AM by Alcaro. |
|
| Posted on 2011-08-30 11:02:16 PM |
Link | Quote |
|
Originally posted by AlcaroGuess: This is some sort of homework, and either your teacher is bad or you want to move faster than the rest of the class.
The latter. Thank you for your help.
|
| Last edited on 2011-08-30 11:02:37 PM by Kipernal. |
|
|
Pages: 1 2  |
|
|
|
|
Forum Index - Hobbies - Computers & Technology - Generic C++ questions |