CGo Convert go string to *C.uchar - c

var originalMsg *C.uchar
C.ecall_pay_w(8, 10, &originalMsg, &signature)
originalMsgStr := fmt.Sprintf("%c", originalMsg)
//Todo convert originalMstStr to same value with originalMsg
i have to convert go str(originalMsgStr) to *C.uchar type which is same value with originalMsg.
How can i do it?

You get a C-string back from your call to C.ecall_pay_w and want to convert that C-string to a Go-string. You can do this by manually following the C-string until you reach the terminating 0.
Assuming that:
There is a terminating 0 at the end of the C-string
The C-string is encoded as ASCII, so every byte represents an ASCII character (in the range [0..127]). This means it is both ASCII and UTF-8 at the same time because UTF-8 is backward compatible to ASCII.
Then your solution could be this:
func convertCStringToGoString(c *C.uchar) string {
var buf []byte
for *c != 0 {
buf = append(buf, *c)
c = (*C.uchar)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + 1))
}
return string(buf)
}
Note that doing "unsafe" things like this in Go is cast-heavy. That was done on purpose by the Go authors. You need to convert to unsafe.Pointer before you can convert to uintptr. The uintptr can be added to (+ 1) while the unsafe.Pointer does not support that. These are the reasons for that much casting.

I do not know Go in much detail, but do not forget that in C the *C.uchar would be something like unsigned char * which is often used to reference a string (Null-terminated array of characters).
Here you use fmt.Sprintf("%c", originalMsg), with %c which expects a single char, so apart from the language detail on how you would cast the resulting string to a *C.uchar, you most probably have lost content already.
%c the character represented by the corresponding Unicode code point
From https://golang.org/pkg/fmt/#hdr-Printing

Related

Converting int64_t to string in C

I am working with C programming language and using Postgres database to insert records. One of the columns of the table in the database is of type timestamp. The data I am getting in the C program is of type int64_t and I need to pass this value as a parameter in the INSERT statement like shown below. In order to do that, I tried to convert the int64_t value to a string using sprintf().
char str[21];
sprintf(str, "%" PRId64 "\n", someTimeReceived inTheProgram);
const char * const paramValues[1] = { str };
PGresult *res = res = PQexecParams(
conn,
"INSERT INTO dummy VALUES(1,to_timestamp($1)::timestamp)",
1, /* one parameter */
NULL,
paramValues,
NULL, /* parameter lengths are not required for strings */
NULL, /* all parameters are in text format */
0 /* result shall be in text format */
);
But on using sprintf(), some garbage value are being inserted at the end of string. For example if the received int64_t value is 132408394771256230 then sprintf() is converting it to 132408394771256230\n\0\003. Because of the extra garbage values appended at the end of string, the program fails to insert the given value and then terminates.
if the received int64_t value is 132408394771256230 then sprintf() is converting it to 132408394771256230\n\0\003
no, sprintf only writes 132408394771256230\n\0 into str and let the rest of the array unchanged, the character of code 3 was present before the call of sprintf (the array is not initialized) but of course it can be anything else.
Because of the extra garbage values appended at the end of string, the program fails to insert the given value and then terminates.
no again, PQexecParams manages params as an array of strings (one string in your case) following the convention a string is ended by a null character, PQexecParams does not read/care about what there is after the null character, and does know even about the 'envelop' of your string (an array of 21 characters in your case).
Your problem probably comes because of the undesirable newline in your string, producing the command to be the string
INSERT INTO dummy VALUES(1,to_timestamp(132408394771256230\n)::timestamp)
just remove \n in the format of your sprintf.
Supposing it is needed to have the newline your array must be sized 22 rather than 21 to manage negative value without an undefined behavior writing out of the array.
...some garbage value
you certainly see the null character and the byte after because you use a debugger and that debugger knows str is sized 21 and when you ask to see the value of str the debugger consider str as an array of characters rather than a string. If you ask your debugger to show (char*) str it will consider str as a string and will not show the null character nor the character after.
[edit]
The function request the date-time as a string yyyy-mm-dd hh:mm:ss rather than your big number being an ua_datetime
To convert an ua_datetime to a the expected string use (see documentation) :
nt ua_datetime_snprintf (char * dst, size_t size, const ua_datetime * dt)
the result is a string YYYY-MM-DDThh:mm:ss.nnnZ so after just replace the last dot by a null character and 'T' by a space (supposing a 'T' is really produced, try and adapt)
An other way is to use :
time_t ua_datetime_to_time_t(const ua_datetime * dt)
then to make your string with standard function from the time_t
Anyway you have to understand you loose a lot of precision, ua_datetime are in 100 nanosecond while *postgress timestamp are in second only

LOGIC of Converting a "char" into an "int" in C

everyone!
please help me understand the following problem...
So i will have a STRING-type input of a note, looks like "A5" or "G#2" or "Cb4" etc. And i need to extract an octave index, which is the last digit "5" or "2" or "4"... And after exctraction i need it as an int-type.
So I did this:
string note = get_string("Input: ");
int octave = atoi(note[strlen(note) - 1]);
printf("your octave is %i \n", octave);
But it gave me an error "error: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'; take the address with & [-Werror,-Wint-conversion]"
Then I tryied to throug away the math from the function, and did this:
int extnum = strlen(note) - 1;
int octave = atoi(note[extnum]);
It didn't work as well. So i did my reserch on atoi function and i don't get it...
ATOI expects a string (CHECK)
Converts it to an interger, not the ASCII meanning (CHECK)
Library for atoi function (CHECK)
What I am doing in basically asking "take n-th character of that string and make it an int".
After googling for some time a found an other code example where a guy uses atoi with this symbol '&'. So i did this:
int octave = atoi(&note[strlen(note) - 1]);
And IT WORKED! But I can't understand WHY it worked with the & symbol and didnt work without it....Cause it always worked without it! There was a million times i was giving a single-character string like '5' or so ond just used atoi and it worked perfectly...
Plesase help me, why in this case it acts so weird?
C does not have a native string type. Strings are usually represented as char array or a pointer to char.
Assuming that string is just a typedef to char *.
if note is an array of chars, note[strlen(note)-1] is just the last character. Since atoi expects a pointer to char (which has to be null-terminated) you have to pass the address of the char and not the value.
The task to convert one char digit to int could also be solved easier:
int octave = note[strlen(note) - 1] - '0';
The function atoi takes a pointer to a character array as the input parameter (const char*). When you call note[strlen(note) - 1] this is a single character (char), in order to make atoi work you need to provide the pointer. You do that by adding & as you've done. This then works, because right after that single digit there is a null character \0 that terminates the string - because your original string was null-terminated.
Note however that doing something like this would not be a good idea:
char a = '7';
int b = atoi(&a);
as there is no way to be sure what the next byte in memory is (following the byte that belongs to a), but the function will try to read it anyway, which can lead to undefined behaviour.
The last character is... well a character! not a string. So by adding the & sign, you made it a pointer to character (char*)!
You can also try this code:
char a = '5';
int b = a - '0';
Gives you ASCII code of 5 minus ASCII code of 0
From the manual pages, the signature of atoi is: int atoi(const char *nptr);. So, you need to pass the address of a char.
When you do this: atoi(note[strlen(note) - 1]) you pass the char itself. Thus, invoking UB.
When you use the &, you are passing what the function expects - the address. Hence, that works.
atoi excepts a string (a pointer to character), not a single character.
However, you should never use atoi since that function has bad error handling. The function strtol is 100% equivalent but safer.
You need to do this in two steps:
Find the first digit in the string.
From there, convert it to integer by calling strtol.
1) can is solved by looping through the string, checking if every item is a digit by calling isdigit from ctype.h. Simultaneously, check for the end of the string, the null terminator \0. When you find the first digit, save a pointer to that address.
2) is solved by passing the saved pointer to strtol, such as result = strtol(pointer, NULL, 10);.

Differentiating between embedded NUL and NUL-terminator

I have a const char* pointing to data in hex format, I need to find the length of the data for that I am checking for NUL-terminator but when \x00 comes up it detects it as NUL-terminator returning incorrect length.
How can I get around that?
const char* orig = "\x09\x00\x04\x00\x02\x00\x10\x00\x42\x00\x02\x00\x01\x80\x0f\x00"
uint64_t get_char_ptr_len(const char *c)
{
uint64_t len = 0;
if (*c)
{
while (c[len] != '\0') {
len++;
}
}
return len;
}
\x00 is the NUL terminator; in facts, \x00 is just another way to write \0.
If you have byte data that contains embedded NULs, you cannot use NUL as a terminator, period; you have to keep both a pointer to the data and the data size, exactly as function that operate on "raw bytes" (such as memcpy or fwrite) do.
As for literals, make sure you initialize an array (and not just take a pointer to it) to be able to retrieve its size using sizeof:
const char orig[] = "\x09\x00\x04\x00\x02\x00\x10\x00\x42\x00\x02\x00\x01\x80\x0f\x00";
Now you can use sizeof(orig) to get its size (which will be one longer than the number of explicitly-written characters, as there's the implicit NUL terminator at the end); careful though, as arrays decay to pointer at pretty much every available occasion, in particular when being passed to functions.
\x indicates hexadecimal notation.
Have a look at an ASCII table to see what \x00 represent.
\x00 = NULL // In Hexadecimal notation.
\x00 is just another way to write \0.
Try
const char orig[] = "\x09\x00\x04\x00\x02\x00\x10\x00\x42\x00\x02\x00\x01\x80\x0f\x00";
and
len=sizeof(orig)/sizeof(char);

convert jchararray to jstring in JNI

I am using JNI below code to convert jchararray to jstring but i am getting only first character in Linux.
char *carr =(char*)malloc(length+1);
(*env)->GetCharArrayRegion(env, ch, 0, length, carr);
return (*env)->NewStringUTF(env, carr);
GetCharArrayRegion returns Java chars, i.e. UTF-16 code points. And jchars in JNI, and they're not null-terminated, and you cannot use NewStringUTF, which expects a null-terminated string comprising bytes in the modified UTF-8 encoding.
First, allocate the correct amount of memory
jchar *carr = malloc(length * sizeof(jchar));
Then execute the GetCharArrayRegion
(*env)->GetCharArrayRegion(env, ch, 0, length, carr);
Then notice that you've got an array of UTF-16 characters. If the first character falls into the ASCII range, and the architecture is little-endian, it is expected that you'd just "get the first character", because the MSB byte of the first jchar will be zero, and NewStringUTF would consider this the terminator. Use NewString instead:
return (*env)NewString(env, carr, length);
You should use the NewString() function which takes jchar array and its length. The NewStringUTF() function takes UTF-8 encoded C string as input.
See https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html#zz-4.2 for more details.

String parsing in C

how would you parse the string, 1234567 into individual numbers?
char mystring[] = "1234567";
Each digit is going to be mystring[n] - '0'.
What Delan said. Also, it's probably bad practice for maintainability to use a ASCII dependent trickery. Try using this one from the standard library:
int atoi ( const char * str );
EDIT: Much better idea (the one above has been pointed out to me as being a slow way to do it) Put a function like this in:
int ASCIIdigitToInt(char c){
return (int) c - '0';
}
and iterate this along your string.
Don't forget that a string in C is actually an array of type 'char'. You could walk through the array, and grab each individual character by array index and subtract from that character's ascii value the ascii value of '0' (which can be represented by '0').

Resources