I'm trying to migrate some managed c++ code to 64bits.
I have a function that gets varargs, and when I pass a System::String variable to it, it appears not to pass correctly.
Here is a simplification of the code that shows the problem:
#include <stdio.h>
#include <stdarg.h>
void test(char* formatPtr, ...)
{
va_list args;
int bufSize;
char buffer[2600];
/////////////////////////////////////
//parse arguments from function stack
/////////////////////////////////////
va_start(args, formatPtr);
bufSize = vsprintf(buffer, (const char*) formatPtr, args);
printf(buffer);
va_end(args);
}
void main() {
System::String^ s;
s = "Shahar";
test("Hello %s", s);
getchar();
}
When this code runs in 32 bits, it displays Hello Shahar.
When it runs in 64 bits, it displays Hello Çz∟⌠■.
Assuming I want to make the least amount of changes to the code, how should I fix this?
It looks as though the problem is in the mix between managed code and varargs. It appears that they are not compatible with each other.
I don't know why this works in 32-bits, but it looks like the wrong thing to do.
I changed the code, so as to be only managed code, with no varargs.
The %s specifier expects a C-style null-terminated string, not a System::String^. C++/CLI headers provide some methods that can convert System::String^ to std::string, which can be converted to a C-string, and can probably just convert straight to a C-string.
You have other problems too. void main()? Assigning a literal to a char*? Fixed-size buffer?
Related
Why is it that in the source code in the SDK for LPNMITEMACTIVATE it is defined with the asterix to the left?
typedef struct tagNMITEMACTIVATE
{
NMHDR hdr;
int iItem;
int iSubItem;
UINT uNewState;
UINT uOldState;
UINT uChanged;
POINT ptAction;
LPARAM lParam;
UINT uKeyFlags;
} NMITEMACTIVATE, *LPNMITEMACTIVATE;
I am always used to the pointer being on the right. Either way, code like:
const LPNMITEMACTIVATE pNMItem = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
Will still flag a const (C26462) warning:
If I change the code to:
const NMITEMACTIVATE* pNMItem = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
The warning will go away.
I tried this with Visual Studio 2022, first of all, warning C26462 was not enabled by default. Perhaps you are using an earlier release, or there is something odd with my installation.
After manually enabling the warning, I could make that warning go away by assigning pNMItem more than once:
LPNMITEMACTIVATE pNMItem = nullptr;
pNMItem = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
How is this useful?
Or it can be fixed as suggested in other answers. But you may have additional problem because pNMHDR was probably declared as LPNMHDR, so you have to rewrite more lines:
NMHDR hdr = { 0 };
const NMHDR* pNMHDR = reinterpret_cast<NMHDR*>(&hdr);
const NMITEMACTIVATE* pNMItem = reinterpret_cast<const NMITEMACTIVATE*>(pNMHDR);
This can be a big waste of time. Note, the extra compliance is recommended if you are writing code that's supposed to run on any system. But MFC is tied to Windows so this isn't really an issue. MFC and Windows are still using that "long pointer" crap that's left over from 16-bit Windows, they are not compliant themselves, so consider turning off some of these warnings.
This is standard C/C++
Like in this (not runnable) code snippet:
typedef int *LPINT;
// typedef int* LPINT; // you could write this, it's exactly the
// the same as above
int main()
{
LPINT pint;
int* pint2;
*pint = *pint2;
}
pint and pint2 are both pointers to int. BTW this is hiding a pointer type behind a typedef, which is a bad idea (but was considered as a good idea in old MS days), but lots of Microsoft headers still have these typedef sometype *LPsometype; typedefs for compatibility reasons.
Another example which is closer to the MS header you're refering to:
This:
typedef struct tagNMITEMACTIVATE
{
int hdr;
int iItem;
} NMITEMACTIVATE, *LPNMITEMACTIVATE;
is equivalent to this:
typedef struct tagNMITEMACTIVATE
{
int hdr;
int iItem;
} NMITEMACTIVATE;
typedef struct tagNMITEMACTIVATE *LPNMITEMACTIVATE;
For pointer const can be applied to the type the pointer points at:
const NMITEMACTIVATE* p;
or
NMITEMACTIVATE const* p;
Or it can be applied to the pointer variable itself:
NMITEMACTIVATE* const p;
Now if you have typedef:
typedef NMITEMACTIVATE *PNMITEMACTIVATE;
The const would not apply to the type being pointed at. Either way it is the pointer itself is constant:
const PNMITEMACTIVATE p;
PNMITEMACTIVATE const p;
To avoid this confusion, prefer not to use raw pointer typedefs (and not to define them).
Here is my simplified code:
static void WriteToFile(const wchar_t* msg) {
FILE* f = fopen("/sdcard/mytest.txt", "w");
fprintf(f, "%ls\n", msg);
fclose(f);
}
// Somewhere else in the code
const wchar_t* msg = L"Hello world";
WriteToFile(msg);
Using %ls to format a wchar string seems to work fine in Windows and Ubuntu. However, on Android, it writes only the first character H in the file.
I even tried to convert wchar to mbs:
char buf[100];
wcstombs(buf, msg, 100);
However, buf still ends up having just one character H in it.
I have a feeling that it is happening because wchar is four bytes long on Android. However, I would think the NDK must be aware of this.
How do I fix this? Regards.
Instead of using wcstombs, etc., use APIs from libiconv (https://www.gnu.org/software/libiconv/). You may have to build libiconv library for Android.
I am studying signals from oreilly book. I came across this.
#include <signal.h>
typedef void (*sighandler_t)(int);----> func ptr returns void. uses typedef
sighandler_t signal (int signo, sighandler_t handler);
Later on in code. He just uses
void sigint_handler (int signo)----> normal function returning void
{
}
can typedef be applied on functions
I want to know how it works
can typedef be applied on functions
Yes.....
I want to know how it works
As the example you have read - the syntax is rather obscure (after 25 years of C I still have to think about it), but it is quite straight forward. Passing and storing pointers to functions is greatly simplified if you use typedefs.
I suggest either take a detour and learn about pointers to functions and typedefs of them, or take it as read for now and return to pointers to function later, as you cannot be a C programmer and avoid them.
A signal is just like a interrupt, when it is generated by user level, a call is made to the kernel of the OS and it will action accordingly. To create a signal, here I just show you an example
#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
void sig_handler1(int num)
{
printf("You are here becoz of signal:%d\n",num);
signal(SIGQUIT,SIG_DFL);
}
void sig_handler(int num)
{
printf("\nHi! You are here becz of signal:%d\n",num);
}
int main()
{
signal(SIGINT,sig_handler1);
signal(SIGQUIT,sig_handler);
while(1)
{
printf("Hello\n");
sleep(2);
}
}
after running this code if you will press Ctrl+C then a message will show - "You are here becoz of signal:2" instead of quiting a process as we have changed a signal according to our action. As, Ctrl+C is a maskable signal.
To know more anbout signals and types of signals with examples please follow the link :
http://www.firmcodes.com/signals-in-linux/
I ahve the following piece of code. I get a correctly filled vector. But I am unable to print or use the vector contents which are file names from a directory. As soon as I do enter the first iteration. Everything gets lost. What am I doing wrong?
wprintf - This works OK
wcout-- here is where everything ends up corrupted
#include <windows.h>
#include <sstream>
#include <string>
#include <vector>
#include<iostream>
void GetAllFiles(vector<LPCWSTR>&, wstring);
using namespace std;
void main (void)
{
vector<LPCWSTR> files(0);
wstring path = L"Datasets\\Persons\\";
wstring ext = L"*.*";
wstring fullPath = path+ext;
GetAllFiles(files,fullPath);
for (unsigned i=0; i<files.size() ; i++)
{
try
{
wcout<<"::\n"<<files[i];
}
catch(exception &ex)
{
cout<<"Error:"<<ex.what();
}
}
}
void GetAllFiles(vector<LPCWSTR>& fileNames,wstring dir)
{
WIN32_FIND_DATA search_data;
memset(&search_data, 0, sizeof(WIN32_FIND_DATA));
HANDLE handle = FindFirstFile(dir.c_str(),&search_data);
while(handle != INVALID_HANDLE_VALUE)
{
wprintf(L"Found file: %s\r\n", search_data.cFileName);
fileNames.push_back(search_data.cFileName);
if(FindNextFile(handle, &search_data) == FALSE)
break;
}
}
I have attached a screen shots of the output.
search_data.cFileName is a pointer to memory controlled by the FindFirstFile/FindNextFile iterator interface; you cannot store this pointer value as the pointed-to memory could change from iteration to iteration (or even be freed after the iteration completes).
Instead, you must make a copy of the string to put in your vector, e.g. using wcsdup. Even better, define your vector as a vector<wstring>, so that push_back(search_data.cFileName); creates a wstring with the contents of search_data.cFileName.
Probably that's happening because you pass local variable to push_back(). I'm not sure here, but what could happen here:
push_back expects object of type LPCWSTR, while you passing char* instead. I don't know, how this conversion is done, but probably the pointer is just copied, and the value of this pointer becomes invalid whenyou return from the function - try explicit copying the strings before passing them to push_back.
Is it possible to change strings (content and size) in Lua bytecode so that it will still be correct?
It's about translating strings in Lua bytecode. Of course, not every language has the same size for each word...
Yes, it is if you know what you're doing. Strings are prefixed by their size stored as an int. The size and endianness of that int is platform-dependent. But why do you have to edit bytecode? Have you lost the sources?
After some diving throught Lua source-code I found such a solution:
#include "lua.h"
#include "lauxlib.h"
#include "lopcodes.h"
#include "lobject.h"
#include "lundump.h"
/* Definition from luac.c: */
#define toproto(L,i) (clvalue(L->top+(i))->l.p)
writer_function(lua_State* L, const void* p, size_t size, void* u)
{
UNUSED(L);
return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
}
static void
lua_bytecode_change_const(lua_State *l, Proto *f_proto,
int const_index, const char *new_const)
{
TValue *tmp_tv = NULL;
const TString *tmp_ts = NULL;
tmp_ts = luaS_newlstr(l, new_const, strlen(new_const));
tmp_tv = &f_proto->k[INDEXK(const_index)];
setsvalue(l, tmp_tv, tmp_ts);
return;
}
int main(void)
{
lua_State *l = NULL;
Proto *lua_function_prototype = NULL;
FILE *output_file_hnd = NULL;
l = lua_open();
luaL_loadfile(l, "some_input_file.lua");
lua_proto = toproto(l, -1);
output_file_hnd = fopen("some_output_file.luac", "w");
lua_bytecode_change_const(l, lua_function_prototype, some_const_index, "some_new_const");
lua_lock(l);
luaU_dump(l, lua_function_prototype, writer_function, output_file_hnd, 0);
lua_unlock(l);
return 0;
}
Firstly, we have start Lua VM and load the script we want to modify. Compiled or not, doesn't matter. Then build a Lua function prototype, parse and change it's constant table. Dump Prototype to a file.
I hope You got that for the basic idea.
You can try using the decompiler LuaDec. The decompiler would allow the strings to be modified in generated Lua code similar to the original source.
ChunkSpy has A No-Frills Introduction to Lua 5.1 VM Instructions that may help you understand the compiled chunk format and make the changes directly to bytecode if necessary.