|
Hello Richard,
Re:
The issue is that you are trying to copy data from a multi-dimensional array using a single dimension pointer; and given the structure of your original array you have no other choice.
It seems to me that what you are not explicitly saying is that we CAN NOT create a pointer to a two dimension array and pass that to another procedure. Is that correct?
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
|
|
|
|
|
No, that's not what I'm saying. A pointer to an array of any size and number of dimensions, points to the elementary item of the array that it references. In your case, that item is a wchar_t so the pointer is defined as pointing to a simple array of characters; that is what gives rise to the problems you are having. If you defined your basic item as a structure rather than an array of characters, then you could make things easier. Something like:
struct dataArray
{
wchar_t item[ MAX_NAME_SIZE ];
} names[COMMON_ARRAY_SIZE];
Set_Pointer(names);
void Set_Pointer(dataArray* new_pointer)
{
dataArray* mp_local_pointer;
mp_local_pointer = new_pointer;
wcscpy_s(one, MAX_NAME_SIZE, dataArray[0].item); wcscpy_s(two, MAX_NAME_SIZE, dataArray[1].item); ...
}
By using a struct rather than a simple array the compiler knows the size of each structure (from its definition) and hence, how to access each individual item when using a pointer to the array of structures.
|
|
|
|
|
Here is my solution that demonstrates passing the pointer and gaining access to the array of strings:
#include "stdafx.h"
const unsigned int COMMON_ARRAY_SIZE = 10;
const unsigned int MAX_NAME_SIZE = 34;
struct st2_names
{
wchar_t names[ COMMON_ARRAY_SIZE ] [ MAX_NAME_SIZE ];
};
void Set_Pointer_2( st2_names *new_pointer );
int _tmain(int argc, _TCHAR* argv[])
{
st2_names names_2;
wcscpy_s( names_2.names[0] , MAX_NAME_SIZE, L"PITCH" );
wcscpy_s( names_2.names[1] , MAX_NAME_SIZE, L"ROLL" );
wcscpy_s( names_2.names[2] , MAX_NAME_SIZE, L"YAW" );
wcscpy_s( names_2.names[3] , MAX_NAME_SIZE, L"VELOCITY" );
Set_Pointer_2( &names_2 );
return 0;
}
void Set_Pointer_2( st2_names *new_pointer )
{
st2_names *mp_names_2;
mp_names_2 = new_pointer;
wchar_t t1[MAX_NAME_SIZE];
wchar_t t2[MAX_NAME_SIZE];
wchar_t t3[MAX_NAME_SIZE];
wchar_t t4[MAX_NAME_SIZE];
wcscpy_s( t1, MAX_NAME_SIZE, mp_names_2->names[0] );
wcscpy_s( t2, MAX_NAME_SIZE, mp_names_2->names[1] );
wcscpy_s( t3, MAX_NAME_SIZE, mp_names_2->names[2] );
wcscpy_s( t4, MAX_NAME_SIZE, mp_names_2->names[3] );
}
It is a but ugly, but does work. EDIT, I did simplify.
It does seem to me that you are saying: No, there is no way to create a simple multi-dimension array such as:
wchar_t names[ x ] [ y ];
and pass a pointer to a procedure, then use that pointer to access all the elements of the array.
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
modified 4-Jul-14 15:30pm.
|
|
|
|
|
bkelly13 wrote: It does seem to me that you are saying No, I have never said that. I have explained a number of different ways how you can use such a pointer, even though it may seem non-intuitive.
And I still think that you are making life more difficult for yourself by not using a simple memcpy to copy the entire structure, since that is all you want in the end result.
|
|
|
|
|
taking things a bit out of order.
The core code, C_AR2_Messages, hands the pointer over to C_Configuration_Manager. That code reads a text file and changes the names adding a prefix to them. When C_AR2_Messages resumes control, it queries another application (a vendor app) to acquire more information about the parameter. So memcopy to C_Configuration Manager does not work out.
Yes, you have given me hints and clues. But I cannot figure out how to change the example code to compile such that the pointer can be saved and used to read and write the array of strings.
I apologize for being rather slow, but do appreciate the time you spend trying to help me.
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
|
|
|
|
|
bkelly13 wrote: I apologize for being rather slow We all had to learn from the beginning to get where we are now. I couldn't begin to understand the basics of telemetry.
However, from your description above I have put together the following. It's making a few (possibly incorrect) assumptions about where the structure should be declared and whether it is the only one you use, but I hope it may give you something to work on.
struct st2_names
{
wchar_t names[ COMMON_ARRAY_SIZE ] [ MAX_NAME_SIZE ];
};
int C_Configuration_Manager(st2_names *new_pointer)
{
wcscpy_s(new_pointer->names[0], MAX_NAME_SIZE, L"PITCH" );
wcscpy_s(new_pointer->names[1], MAX_NAME_SIZE, L"ROLL" );
wcscpy_s(new_pointer->names[2], MAX_NAME_SIZE, L"YAW" );
wcscpy_s(new_pointer->names[3], MAX_NAME_SIZE, L"VELOCITY" );
return 0;
}
int C_AR2_Messages(st2_names *dataPointer)
{
C_Configuration_Manager(dataPointer);
CallOtherFunction(dataPointer);
return 0;
}
int wmain(int argc, wchar_t* argv[])
{
st2_names dataNames;
memset(&dataNames, 0, sizeof dataNames);
C_AR2_Messages(&dataNames);
return 0;
}
|
|
|
|
|
Hello,
If it was in the cards for you, you could easily deal with telemetry.
Good answer. That will work.
Additionally, I have been busy. The problem with my code was one of precedence. Here are, hopefully, the core lines that show how the procedure can be declared and defined.
const wchar_t prefix[ SIZE_OF ] = L"S01_";
void Set_Pointer( wchar_t (*new_pointer)[COUNT_OF][SIZE_OF] )
{
foo_names = new_pointer;
swprintf_s( (*foo_names)[0],SIZE_OF, L"%s%s", prefix, c0 );
}
Character * is a prefix and the postfix [] is bound first. The parenthesis causes the * to be bound to the name before the [].
Obviously, the fragment does nothing useful, but it shows what to do.
Putting it all in a structure is the easy way and I have used enough structures to have thought of that much earlier. Now I have both methods.
I really should print out a list of all the precedencies and put them on the wall next to me. With large type so I can read it without getting up.
There is a third way, using a friend class. Then it does not even need to be passed. (A tool to be used sparingly.) I tried that and failed. Time to hit the books and search engine and see what I did wrong there.
Thank you for your time and thank you for your patience.
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
|
|
|
|
|
Well worked out, I had forgotten about the precedence issue (but at my age I forget lots of stuff). Good luck with the rest of the work.
|
|
|
|
|
Windows 7, Visual Studio 2008, C++, MFC
I cannot cut and paste to this forum so please exclude minor typos.
Here is the first class declaration:
Class C_AR2_Messages
Public:
Class C_AR2_Messages();
~ Class C_AR2_Messages();
Private:
…
// friend void_C_Configuration_Manager( const C_AR2_Messages & );
// I found the template for this somewhere and presume that C_Configuration_Manager needs to be given the address of AR2_Messages so it can find variables declared private.
};
A fragment from the definition of C_AR2_Messages:
bool C_AR2_Messages::Configure_The_Application()
{
C_Configuration_Manager *Message_Configurator;
Message_Configurator = new C_Configuration_Manager;
… }
This all compiles as shown with no errors.
HOWEVER: when the friend line is uncommented out the compiler complains with the error:
Quote: C2061: ‘Message_Configurator’ : undeclared identifier.
It references that line so marked above. (Not the "friend" line in the declaration.) Since that is a pointer declaration I do not understand how the addition of the friend line causes it to become undeclared.
A google search returned what seems to be a good match for this problem, but I am on a military base and the firewall says that site is prohibited.
Will someone please enlighten me?
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
modified 30-Jun-14 12:24pm.
|
|
|
|
|
It needs a forward declaration of void_C_Configuration_Manager class.
Do as follows.
class void_C_Configuration_Manager;
Do it in the header.
|
|
|
|
|
Windows 7, Visual Studio, C++, MFC dialog
A MFC dialog calls _beginthreadex and starts procedure Start_Server_As_Thread as a new thread.
That procedure instantiates class C_Server_Thread then calls a method that loops until an event indicates time to exit. That class creates a new instance of C_Log_Writer to write information to a log file.
The appropriate event is set, and the main loop exits.
Immediately on regaining control, procedure Start_Server_As_Thread deletes the class with:
delete mp_C_Server_Thread;
The destructor of that class is not called. The destructor contains the code
delete mp_C_Log_Writer;
which does not get run resulting in a memory leak.
I was under the impression that explicitly deleting an instance of a class forced the destructor to be called. What should I do to get that destructor called?
In the code that detects said event I can add a line to delete the logger class. Still, the question will remain, why is the destructor not called?
Edit:
Just for completeness, a silly mistake that I looked right at several times before finally stepping through the code one step at a time.
if( mp_C_Log_Writer == NULL )
{
delete mp_C_Log_Writer;
mp_C_Log_Writer = NULL;
The == should have been !=. Lesson learned again, always step through every line of code with the debugger at least once. Sorry to trouble anyone over this.
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
modified 29-Jun-14 16:55pm.
|
|
|
|
|
Is mp_C_Server_Thread of type C_Server_Thread* , or a base class? If it is abase class pointer, and the base class does not have a virtual destructor, the derived class destructor will not be called.
You are right, calling delete on a pointer will call the pointer type's destructor, if any, but without more code to look at it's very hard to say what the problem might be. For instance, are you absolutely sure that Start_Server_As_Thread does regain control, and that the delete call is executed?
|
|
|
|
|
Here is the procedure that is started as the new thread. It instantiates a class then runs the main method of that class.
unsigned int __stdcall Start_Server_As_Thread( void * p_void_pointer )
{
C_Server_Thread *mp_C_Server_Thread = NULL;
WCHAR m_log_file_text[ MAX_LOG_STRING_LENGTH ];
mp_C_Server_Thread = new C_Server_Thread( p_void_pointer );
mp_C_Server_Thread->Main_Thread_Loop();
delete mp_C_Server_Thread;
mp_C_Server_Thread = NULL;
_endthreadex( 0 );
return 0;
}
That class is declared as follows
class C_Server_Thread
{...}
The class it creates is declared:
class C_TCP_API_Server
{...}
Class C_Server_Thread manages all the overhead and communications between the main app and the thread. It instantiates C_TCP_API_Server, which does all the low level work of establishing a TCP/IP link with the client and sending the data.
Does that provide any useful information?
Edit: I continue to work this and am not certain where the problem is, but am becoming more certain that PEBKAC (Problem Exists Between Keyboard And Chair). It is looking more and more like a logic error in how I end this thing. Class C_Server_Thread could be in any of several states when it gets the event to exit. (Not connected to client, connected to client, sending data, etc) I need to work over the logic of what should be done for each state to ensure an orderly shutdown, not to mention complete shutdown.
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
modified 27-Jun-14 21:26pm.
|
|
|
|
|
Windows 7, Visual Studio 2008, C++
I am creating a console type application that uses events and an MFC dialog app just to test it. The app uses WaitForMultipleObjects() with the attendant array of events. The dialog will show the count of events set and detected. The code to update the dialog and show those counts begins like this:
void CTest_ServerDlg::OnBnClickedBtnUpdateThreadEvents()
{
const unsigned int NUMBER_SIZE = 8;
WCHAR text_value[ NUMBER_SIZE ];
int t;
t = m_common_data.thread_event_detects[ 0 ];
swprintf_s( text_value, NUMBER_SIZE, L"%03D", t );
m_thread_event_00.SetWindowTextW( text_value );
}
m_thread_event_00 is the name of the control variable assigned to the static text control in the dialog. Presume there are 16 events. I am new to Dialogs and their controls so that means there will be 16 static text controls, each with its own named variable.
The Question:
Can this setup be arranged so that the values can be updated via an iteration rather than copying the last three lines 15 more times and changing the thread_event_detects[ 0 ] and m_thread_event_00 to increment up to 15?
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
|
|
|
|
|
Yes, you can use GetDlgItem()[^] on the static window's resource ID (returns CWnd* but you can cast that to whatever you need). As long as your resource IDs are contiguous, you can start at the first resource ID and increment the value as you iterate through them. Check the resource file for the actual numbers associated with the ID.
|
|
|
|
|
Windows 7 and XP, Visual Studio 2008, 2010, C++, MFC, Windows 32 application.
I am getting frustrated with the various types of strings. With all the articles I find and often opposing points of view, I wish to limit my options and seek your opinion.
I write telemetry code that must run quite fast and move much data. The strings I deal with are mostly to log data so I can see how the code works. The end product will be a windows application that really needs no user interface.
However, during development, and because a vendor uses MFC and C++, I wish to develop in that environment. I have no desire to explicitly exclude other operating systems, but I really do not expect to use anything other than Windows XP and Windows 7 any times soon.
Which option is best: WCHAR, wchar_t, CString, char[], or something else?
edit: I forgot that WCHAR is just a typedef of wchar_t. Which does not seem very bright. Would it be wise to drop all use of WHAR and replace with wchar_t?
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
modified 13-Jun-14 11:08am.
|
|
|
|
|
IT depends on what you are trying to do, and what may change in the future. If you want a simple self-managing string type and you have MFC, then use CString . If you want speed and more control of the string data then use character arrays. If you choose the latter course then your decision will be based on the type of data that you are processing: if it is ASCII data then use char arrays, if Unicode use WCHAR arrays.
|
|
|
|
|
The fundamental purpose is to capture telemetry data, all numbers, reformat them, and send them to another computer.
HOWEVER: as often needed, I need insight into the application. Keeping this short: An MFC is used and sometimes an AFXMsgBox window is needed to inform the user of errors detected. There is also a log file. It needs to be read to see how the program operated.
Does that help narrow the field?
Edit:
I read that I really should switch to Unicode, so I did and started using WCHAR. Now I discovered that it is just a retype of wchar_t, and further that it is Microsoft unique. I do not expect to write code that can be dropped into a Unix machine and compiled, but would like to be reasonably compatible. So what the heck should be used?
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
modified 13-Jun-14 16:27pm.
|
|
|
|
|
bkelly13 wrote: Does that help narrow the field? Not really, since all of those issues may be handled in ASCII or Unicode without any problems. You omitted to explain the format of the input data: numbers as in characters (ASCII or Unicode), or numbers as in binary values? And, if the latter what do you convert them into (if anything).
If you are using Unicode for all your text then stick with WCHAR, since it's a macro and can be defined to equate to any native unicode type on other platforms.
|
|
|
|
|
The data is received as binary values and is signed, unsigned, with sizes from 1 bit per parameter to 32 bits. Some value are floating point number. All binary format, no text in any form. My application picks them out of the stream, shifts them into the correct position, applies scale and offset, assigns identifying tag numbers, and TCP the data out to a display device.
The text is used to create a configuration file for each of the different telemetry types. That is done with VBA for Excel that I write. Log files that show performance are in a text format that are read with Microsoft Wordpad. The startup configuration work and the performance monitoring use text. All the primary operations are shuffling binary data around and do not use any text.
Your comment that WCHAR can be redefined to something else for another device was a revelation. Simple and obvious and completely missed. It makes a rather big difference. Thank you for the idea.
I was thinking of std::string. Do you think that would be a valid choice? Because of your comment it is not as likely, but I would like to hear you thoughts on that anyway.
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
|
|
|
|
|
bkelly13 wrote: I was thinking of std::string That would also be a valid choice, although be aware that std::string is ASCII only, for Unicode you need to use std::wstring . I tend to use a typedef to define my own type which will be ASCII or Unicode, dependiing on the project settings. Something like:
#if defined(UNICODE)
typedef std::wstring STRING;
#else
typedef std::string STRING;
#endif
Then I just use STRING everywhere in the rest of the code, and the compiler sorts it out for me.
From your comments above and the description of what your code is required to do, it seems that the choice is far less important than your first message implied.
|
|
|
|
|
Re: well, yes and no. It is less important on this particular project. It is more important in that as I become used to one type or the other I will tend to use it on subsequent projects.
Not very many people/places are heavy into telemetry and some of those are unix/linix shops. WCHAR is fine, but I am thinking that std::wstring might be the better option. The TCP/IP will make it difficult to port, but I can do little about that. (Well, not true, but out of scope.)
Thank you for taking the time to reply.
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
|
|
|
|
|
bkelly13 wrote: The TCP/IP will make it difficult to port If you stick to the basic TCP/IP functions (connect , listen , send , recv ) it will port with no problems.
|
|
|
|
|
I am writing this to use non-blocking and overlapped with events to signify I/O completion. The WSA* calls are used. Does that reduce portability?
Thank you for your time
If you work with telemetry, please check this bulletin board: www.irigbb.com
|
|
|
|
|
Yes, WSA functions are all Windows sockets, so not directly portable. Although you could always write some code of your own to cater for that if necessary.
|
|
|
|
|