l used ANDROID NDK 。so l want to format something。just use sprintf,but l can not use it with
wchar_t. is there some helps for me?
You probably want swprintf and friends, assuming Android has it like Posix and Linux systems.
Glib (from GTK) has functions for unicode manipulation and for string utilities. I believe you should be able to make it work on Android.
In Android OS NDK versions before 5.0 ("Lollipop"), the sprintf() does not support the "%ls" (wchar_t pointer) format specifier. Thus, the following statement compiles but does not execute correctly under NDK (pre-5.0):
char buffer [1000];
wchar_t *wp = L"wide-char text";
sprintf (buffer, "My string is: %ls", wp);
The workaround is to convert the wchar_t string to UTF-8 (which is a char *) using any one of the Open Source wide-to-utf8 implementations (e.g. the UTF8-CPP project), passing its pointer to sprintf:
// WcharToUtf8: A cross-platform function I use for converting wchar_t string
// to UTF-8, based on the UTF8-CPP Open Source project
bool WcharToUtf8 (std::string &dest, const wchar_t *src, size_t srcSize)
{
bool ret = true;
dest.clear ();
size_t wideSize = sizeof (wchar_t);
if (wideSize == 2)
{
utf8::utf16to8 (src, src + srcSize, back_inserter (dest));
}
else if (wideSize == 4)
{
utf8::utf32to8 (src, src + srcSize, back_inserter (dest));
}
else
{
// sizeof (wchar_t) is not 2 or 4 (does it equal one?)! We didn't
// expect this and need to write code to handle the case.
ret = false;
}
return ret;
}
...
char buffer [1000];
wchar_t wp = L"wide-char text";
std::string utf8;
WcharToUtf8 (utf8, wp, wcslen (wp));
sprintf (buffer, "My string is: %s", utf8.c_str ());
Starting with Android 5.0 ("Lollipop"), sprintf() supports the "%ls" format specifier, so the original sprintf() code above works correctly.
If your Android NDK code needs to run on all version of Android, you should wrap all your wchar_t pointers passed to sprintf with a macro like the following:
#define CONVERTFORANDROID(e) (GetSupportsSprintfWideChar () ? (void *) e : (void *) WcharToUtf8(e).c_str ())
char buffer [1000];
wchar_t *wp = L"wide-char text";
sprintf (buffer, "My string is: %ls", CONVERTFORANDROID(wp));
The GetSupportsSprintfWideChar() function should be a local function that returns true if the running Android OS is 5.0 or above, while returning false if the OS is pre-5.0.
Related
I am creating a currency converter Win32 program in Embarcadero C++Builder. I wrote a function for transforming date from format specified on user PC to YYYY-MM-DD format. I need that part because of API settings.
When I have this function inside my project it works fine, but I need to have that function inside a DLL.
This is how my code looks like:
#pragma hdrstop
#pragma argsused
#include <SysUtils.hpp>
extern DELPHI_PACKAGE void __fastcall DecodeDate(const System::TDateTime DateTime, System::Word &Year, System::Word &Month, System::Word &Day);
extern "C" UnicodeString __declspec (dllexport) __stdcall datum(TDateTime dat) {
Word dan, mjesec, godina;
UnicodeString datum, datum_dan, datum_mjesec, datum_godina;
DecodeDate(dat, godina, mjesec, dan);
if (dan<=9 && mjesec<=9) {
datum_dan="0"+IntToStr(dan);
datum_mjesec="0"+IntToStr(mjesec);
}
if (dan<=9 && mjesec>9) {
datum_dan="0"+IntToStr(dan);
datum_mjesec=IntToStr(mjesec);
}
if (dan>9 && mjesec<=9) {
datum_dan=IntToStr(dan);
datum_mjesec="0"+IntToStr(mjesec);
}
if (dan>9 && mjesec>9) {
datum_dan=IntToStr(dan);
datum_mjesec=IntToStr(mjesec);
}
datum_godina=IntToStr(godina);
return datum_godina+"-"+datum_mjesec+"-"+datum_dan;
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
`
I've included SysUtils.hpp and declared DecodeDate() function, without those lines I have a million errors. But with code looking like this, I am getting this error, which I can't get rid of:
[bcc32 Error] File1.cpp(30): E2015 Ambiguity between '_fastcall System::Sysutils::DecodeDate(const System::TDateTime,unsigned short &,unsigned short &,unsigned short &) at c:\program files (x86)\embarcadero\studio\19.0\include\windows\rtl\System.SysUtils.hpp:3466' and '_fastcall DecodeDate(const System::TDateTime,unsigned short &,unsigned short &,unsigned short &) at File1.cpp:25'
Full parser context
File1.cpp(27): parsing: System::UnicodeString __stdcall datum(System::TDateTime)
Can you help me to get rid of that error?
The error message is self-explanatory. You have two functions with the same name in scope, and the compiler doesn't know which one you want to use on line 30 because the parameters you are passing in satisfy both function declarations.
To fix the error, you can change this line:
DecodeDate(dat, godina, mjesec, dan);
To either this:
System::Sysutils::DecodeDate(dat, godina, mjesec, dan);
Or this:
dat.DecodeDate(&godina, &mjesec, &dan);
However, either way, you should get rid of your extern declaration for DecodeDate(), as it doesn't belong in this code at all. You are not implementing DecodeDate() yourself, you are just using the one provided by the RTL. There is already a declaration for DecodeDate() in SysUtils.hpp, which you are #include'ing in your code. That is all the compiler needs.
Just make sure you are linking to the RTL/VCL libraries to resolve the function during the linker stage after compiling. You should have enabled VCL support when you created the DLL project. If you didn't, recreate your project and enable it.
BTW, there is a MUCH easier way to implement your function logic - instead of manually pulling apart the TDateTime and reconstituting its components, just use the SysUtils::FormatDateTime() function or the TDateTime::FormatString() method instead, eg:
UnicodeString __stdcall datum(TDateTime dat)
{
return FormatDateTime(_D("yyyy'-'mm'-'dd"), dat);
}
UnicodeString __stdcall datum(TDateTime dat)
{
return dat.FormatString(_D("yyyy'-'mm'-'dd"));
}
That being said, this code is still wrong, because it is not safe to pass non-POD types, like UnicodeString, over the DLL boundary like you are doing. You need to re-think your DLL function design to use only interop-safe POD types. In this case, change your function to either:
take a wchar_t* as input from the caller, and just fill in the memory block with the desired characters. Let the caller allocate the actual buffer and pass it in to your DLL for populating:
#pragma hdrstop
#pragma argsused
#include <SysUtils.hpp>
extern "C" __declspec(dllexport) int __stdcall datum(double dat, wchar_t *buffer, int buflen)
{
UnicodeString s = FormatDateTime(_D("yyyy'-'mm'-'dd"), dat);
if (!buffer) return s.Length() + 1;
StrLCopy(buffer, s.c_str(), buflen-1);
return StrLen(buffer);
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
wchar_t buffer[12] = {};
datum(SomeDateValueHere, buffer, 12);
// use buffer as needed...
int len = datum(SomeDateValueHere, NULL, 0);
wchar_t *buffer = new wchar_t[len];
int len = datum(SomeDateValueHere, buffer, len);
// use buffer as needed...
delete[] buffer;
allocate a wchar_t[] buffer to hold the desired characters, and then return a wchar_t* pointer to that buffer to the caller. Then export a second function that the caller can pass the returned wchar_t* back to you so you can free it correctly.
#pragma hdrstop
#pragma argsused
#include <SysUtils.hpp>
extern "C" __declspec(dllexport) wchar_t* __stdcall datum(double dat)
{
UnicodeString s = FormatDateTime("yyyy'-'mm'-'dd", dat);
wchar_t* buffer = new wchar_t[s.Length()+1];
StrLCopy(buffer, s.c_str(), s.Length());
return buffer;
}
extern "C" __declspec(dllexport) void __stdcall free_datum(wchar_t *dat)
{
delete[] dat;
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
wchar_t *buffer = datum(SomeDateValueHere);
// use buffer as needed...
free_datum(buffer);
I am trying to compile a project that was previous using /oldsyntax, but now with /clr.
std::string Jhc::Interop::stlString(System::String^ s)
{
std::string out;
const wchar_t __pin * str = PtrToStringChars(s);
int len = s->Length*4;
char *buf = new char[len];
memset(buf,len,0);
I have changed System::String *s to System::String^ s, but how do I covert the line with PtrToStringChars(s);?
I have tried using pin_ptr and interior_ptr, but cannot make it work.
I have a string in a uint8_t str[] array and I am trying to store the positions of characters within the str in another variable called uint8_t pos[]. The code is written in Code Composer Studio vs 5.4
I tried using sprintf(), type casting as well as changing the type of uint8_t pos[] to int pos[] as well as unsigned int pos[]. None of these work.
The code breaks at the sprintf statement and comes to a halt by reaching an undefined memory location. When I run in assembly after reaching sprintf statement, it gives an error saying that a source code for sprint.c cannot be found in location.
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "tm4c123gh6pm.h"
#include <stdio.h>
void initHw()
{
.
.
}
int main(void)
{
// Initialize hardware
initHw();
char strRx[80];
int count =0;
int count_enter=0;
uint8_t posStr[80];
uint8_t typeStr[80];
int pos=0;
int len;
unsigned int j=0, argCount=0;
while(1)
{
if(count == 0)
{
putsUart0("Enter characters for the string\r\n");
}
if(count <= 80)
{
char c = getcUart0();
if(c=='\b')
if(count>0)
count--;
else
break;
if(c>=' ')
{
strRx[count]=c;
count++;
}
if(count==80 || c==13)//'\r')
{
count_enter++;
if(count_enter==1) //count==80 before carriage return
{
len = count;
strRx[count]='\0';
while(count!=80)
strRx[count++]='\0';
count_enter=0;
putsUart0("\r\nEntered string is:\r\n");
putsUart0(strRx);
putsUart0("\r\n");
}
j=0;
//char a[10];
for(pos=0; pos!=len; pos++)// strRx[pos]!='\0'; pos++)
{
char a[80];
if((strRx[pos]>='A' && strRx[pos]<='Z') || (strRx[pos]>='a' && strRx[pos]<='z'))
{
typeStr[j]='a';
//posStr[j]=pos;
a[j]=pos;
sprintf(a,"%u",pos); //source not found
//a[j]=pos;
//posStr[j]=sprintf("%c",a);
//posStr[j]=(uint8_t)a;//a;
while(strRx[pos]!='\0'&&((strRx[pos]>='A' && strRx[pos]<='Z') || (strRx[pos]>='a' && strRx[pos]<='z')))
{
pos++;
}
pos--;
j++;
}
else if(strRx[pos]>='0' && strRx[pos]<='9')
{
typeStr[j]='n';
a[j]=pos;
sprintf(a,"%u",pos);
//posStr[j]=pos;//a;
while(strRx[pos]!='\0'&&((strRx[pos]>='0' && strRx[pos]<='9')))
{
pos++;
}
pos--;
j++;
}
else
{
while(strRx[pos]!='\0'&&((strRx[pos]<'A' && strRx[pos]>'Z') && (strRx[pos]<'a' && strRx[pos]>'z') && (strRx[pos+1]<'0' && strRx[pos+1]>'9')))
pos++;
}
}
argCount=j;
while(j!=80)
{
typeStr[j++]='\0';
posStr[j++]='\0';
}
count = 0;
}//if(count==80 || c==13)//'\r')
}//if count<=80
}//while(1)
}//main
The "unable to locate sprintf.c" error probably just means that the debugger cannot locate the source file, which means it cannot show the source code in the debugger window. It's possible that you don't have the source code for sprintf.c and all you have is the precompiled library. Or maybe you do have the source code and the debugger is simply looking in the wrong path. If you have the source code then there may be a way to tell the debugger which path to find it.
But that is just a debugger display issue -- It is not what is causing your program to crash. The problem may be in your code but you'd have to share your code for us to identify that. Or the problem may be a couple other issues that can occur with the printf related routines.
1) printf routines can use a relatively large amount of stack space. So check for a stack overflow and increase the stack size if necessary.
2) Some embedded libraries provide multiple implementations of the printf routines such as "small", "no-float", and "full". The limited implementations use less code space but don't support all of the format specifiers. So make sure the implementation of sprintf that you've linked with supports all the format specifiers that you're actually using. Look through the project settings under linker or libraries for an option to select which version of printf is used.
Given I have a type specifier as returned by method_copyReturnType(). In the GNU runtime delivered with the GCC there are various methods to work with such a type specifier like objc_sizeof_type(), objc_alignof_type() and others.
When using the Apple runtime there are no such methods.
How can I interpret a type specifier string (e.g. get the size of a type) using the Apple runtime without implementing an if/else or case switch for myself?
[update]
I am not able to use the Apple Foundation.
I believe that you're looking for NSGetSizeAndAlignment:
Obtains the actual size and the aligned size of an encoded type.
const char * NSGetSizeAndAlignment (
const char *typePtr,
NSUInteger *sizep,
NSUInteger *alignp
);
Discussion
Obtains the actual size and the aligned size of the first data type represented by typePtr and returns a pointer to the position of the next data type in typePtr.
This is a Foundation function, not part of the base runtime, which is probably why you didn't find it.
UPDATE: Although you didn't initially mention that you're using Cocotron, it is also available there. You can find it in Cocotron's Foundation, in NSObjCRuntime.m.
Obviously, this is much better than rolling your own, since you can trust it to always correctly handle strings generated by its own runtime in the unlikely event that the encoding characters should change.
For some reason, however, it's unable to handle the digit elements of a method signature string (which presumably have something to do with offsets in memory). This improved version, by Mike Ash will do so:
static const char *SizeAndAlignment(const char *str, NSUInteger *sizep, NSUInteger *alignp, int *len)
{
const char *out = NSGetSizeAndAlignment(str, sizep, alignp);
if(len)
*len = out - str;
while(isdigit(*out))
out++;
return out;
}
afaik, you'll need to bake that info into your binary. just create a function which returns the sizeof and alignof in a struct, supports the types you must support, then call that function (or class method) for the info.
The program below shows you that many of the primitives are just one character. So the bulk of the function's implementation could be a switch.
static void test(SEL sel) {
Method method = class_getInstanceMethod([NSString class], sel);
const char* const type = method_copyReturnType(method);
printf("%s : %s\n", NSStringFromSelector(sel).UTF8String, type);
free((void*)type);
}
int main(int argc, char *argv[]) {
#autoreleasepool {
test(#selector(init));
test(#selector(superclass));
test(#selector(isEqual:));
test(#selector(length));
return 0;
}
}
and you could then use this as a starting point:
typedef struct t_pair_alignof_sizeof {
size_t align;
size_t size;
} t_pair_alignof_sizeof;
static t_pair_alignof_sizeof MakeAlignOfSizeOf(size_t align, size_t size) {
t_pair_alignof_sizeof ret = {align, size};
return ret;
}
static t_pair_alignof_sizeof test2(SEL sel) {
Method method = class_getInstanceMethod([NSString class], sel);
const char* const type = method_copyReturnType(method);
const size_t length = strlen(type);
if (1U == length) {
switch (type[0]) {
case '#' :
return MakeAlignOfSizeOf(__alignof__(id), sizeof(id));
case '#' :
return MakeAlignOfSizeOf(__alignof__(Class), sizeof(Class));
case 'c' :
return MakeAlignOfSizeOf(__alignof__(signed char), sizeof(signed char));
...
When will the _vsnprintf crash?
I use it like this:
void My_Printf(const char *szFormatString, ...)
{
va_list my_args;
va_start(my_args, szFormatString);
AppendToLog(szFormatString, my_args);
va_end(my_args);
}
static void AppendToLog(const char *szFormatString, va_list argptr)
{
char szLine[MAX_LENGTH_STRING] = {0};
if ((NULL != szFormatString) && (0 != strcmp(szFormatString, ""))) {
if (strlen(szFormatString) > MAX_LENGTH_STRING) {
return;
}
#ifdef WIN32
_vsnprintf(szLine, MAX_LENGTH_STRING-1, szFormatString, argptr);
#endif
...
}
and the VC show that it was broken at:
_VALIDATE_RETURN( (ch != _T('\0')), EINVAL, -1); (output.c)
I don't know why.
According to MSND, it should return a value whether it was ok or not.
This is canonical code for using vsnprintf:
void Format( const char * fmt, ... ) {
const int BUFSIZE = 1024;
char buffer[BUFSIZE];
va_list valist;
va_start( valist, fmt );
vsnprintf( &buf[0], BUFSIZE, fmt, valist );
va_end( valist );
// do something with buffer
}
I don't know if this helps, but keep in mind that vsnprintf (and _vsnprintf I guess since Microsoft says they're identical) return different values on Windows and Unix. The Windows version returns -1 if you overflow the buffer, while the Unix version returns how many characters would have been written had the buffer been large enough. Here's a couple of links that I found helpful in this regard:
http://msdn.microsoft.com/en-us/library/1kt27hek(v=vs.80).aspx
http://bytes.com/topic/c/answers/590845-snprintf-return-value
EDIT: And here's an alternate version I found to get around this problem:
http://article.gmane.org/gmane.comp.version-control.git/75280/