I'm trying to learn how to access c++ library from c, I understood I've to use extern "C", in order to test it, I started with the below working c code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void c_free_string(const char *str){
free(str);
}
char *concat(const char *str1, const char *str2)
{
char *res;
const char del[] = ", ";
res = malloc(strlen(str1) + strlen(str2) + strlen(del) + 1);
if (!res) {
fprintf(stderr, "malloc() failed: insufficient memory!\n");
return EXIT_FAILURE;
}
strcpy(res, str1);
strcat(res, del);
strcat(res, str2);
printf("Result: '%s'\n", res);
return res;
}
int main(void) {
const char str1[] = "First";
const char str2[] = "Second";
char* s = concat(str1, str2);
printf("Result: '%s'\n", s);
c_free_string(s);
return EXIT_SUCCESS;
}
I wanted to write the equivalent c++ code of the above
I want to be ensure using the correct declaration to be able to do c binding with the lib generated from this c++ code.
I started with the belowm but stuck:
#include <iostream>
#include <sstream>
extern "C"
void c_free_string(const char *str){
free(str);
}
extern "C"
char *concat(const char *str1, const char *str2)
{
std::cout << "Hello from C++";
stringstream ss;
ss << str1 << ", " << str2;
string res = ss.str();
std::cout << "Result: "<<res;
return res;
}
Thanks for the comments, the answer looks to be:
#include <iostream>
#include <sstream>
extern "C"
void c_free_string(char *str){
free(str);
}
extern "C"
char *concat(const char *str1, const char *str2)
{
printf("welcome from c++\n");
char *res;
const char del[] = ", ";
res = (char*) malloc(strlen(str1) + strlen(str2) + strlen(del) + 1);
if (!res) {
fprintf(stderr, "malloc() failed: insufficient memory!\n");
exit(EXIT_FAILURE);
}
strcpy(res, str1);
strcat(res, del);
strcat(res, str2);
printf("Result: '%s'\n", res);
return res;
}
UODATE
A cleaner version based on Paul McKenzie feedback:
#include <iostream>
#include <string>
#include <cstring>
extern "C"
void c_free_string(char *str){
delete [] str;
}
extern "C"
char *concat(const char *str1, const char *str2)
{
const char* del = ", ";
int len1 = strlen(str1);
int len2 = strlen(del);
int len3 = strlen(str2);
char *res = new char [len1 + len2 + len3 + 1]{};
strcpy(res, str1);
strcpy(res + len1, del);
strcpy(res + len1 + len2, str2);
return res;
}
int main()
{
char *test = concat("abc", "123");
std::cout << test;
c_free_string(test);
}
Related
there is code
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
int main() {
const char key[] = "012345678";
char data[] = "hello world";
unsigned char* result;
unsigned int len = 20;
result = (unsigned char*)malloc(sizeof(char) * len);
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, key, strlen(key), EVP_sha1(), NULL);
HMAC_Update(&ctx, (unsigned char*)&data, strlen(data));
HMAC_Final(&ctx, result, &len);
HMAC_CTX_cleanup(&ctx);
printf("HMAC digest: ");
for (int i = 0; i != len; i++)
printf("%02x", (unsigned int)result[i]);
printf("\n");
free(result);
}
output HMAC digest: e19e220122b37b708bfb95aca2577905acabf0c0
I can not update this code for openssl 1.1.0.
The new version changed the syntax hmac.
#include <iostream>
#include <string.h>
#include <openssl/hmac.h>
using namespace std;
int main() {
const char key[] = "012345678";
char data[] = "hello world";
int datalen = strlen(data);
int keylen = strlen(key);
unsigned char* result;
unsigned int len = 20;
result = (unsigned char*)malloc(sizeof(char) * len);
cout << datalen << endl;
cout << keylen << endl;
cout << len << endl;
HMAC_CTX *HMAC_CTX_new();
int HMAC_CTX_reset(HMAC_CTX *ctx);
int HMAC_Init_ex(HMAC_CTX *ctx, const char key, int keylen, const EVP_MD EVP_sha1());
int HMAC_Update(HMAC_CTX * ctx, char &data, int datalen);
int HMAC_Final(HMAC_CTX * ctx, char result, int &len);
int HMAC_CTX_cleanup(HMAC_CTX * ctx);
printf("HMAC digest: ");
for (int i = 0; i != len; i++)
printf("%02x", (unsigned int)result[i]);
printf("\n");
free(result);
return 0;
}
output HMAC digest: 0000000000000000000000000000000000000000
I will be glad of any help
Why does strcat gives me its version of str1? As far as I know there has to be & thing before paramatater in function prototype and implementation if you want to get it editted, but I don't see it here.
char *strcat( char *str1, const char *str2 );
How do I edit this function so that it would only return new string but leave out the ones I give it?
My try
char *strApp(char *dest, const char *src)
{
size_t i,j;
size_t k = 0;
for (i = 0; dest[i] != '\0'; i++);
char rdest[100];
do {
rdest[k] = dest[k];
} while(++k<=i);
for (j = 0; src[j] != '\0'; j++)
rdest[i+j] = src[j];
rdest[i+j] = '\0';
return rdest;
}
It damages second string. Could anyone give me safe and correct version? Thanks in advance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *strApp(const char *s1, const char *s2)
{
char *pointer = malloc(strlen(s1) + strlen(s2) + 1);
if (pointer == NULL)
{
perror("failed to allocate memory");
exit(EXIT_FAILURE);
}
return strcat(strcpy(pointer, s1), s2);
}
int main()
{
char *s1 = "original";
char *s2 = " modified";
char *s3 = strApp(s1, s2);
printf("%s\n", s1);
printf("%s\n", s2);
printf("%s\n", s3);
free(s3);
return 0;
}
Just trying to point out you don't need to completely rewrite strcat() to get what you want.
strcat is, by definition, altering the target. If you don't want to, you should make a copy yourself in a target memory location you allocate yourself.
You've tagged your question with both C and C++. I'm providing a C solution. Adjustments may be needed for C++.
#include <stdlib.h>
#include <string.h>
char* strdupcat(const char* s1, const char* s2) {
size_t s1_len = strlen(s1);
size_t s2_len = strlen(s2);
char* s = malloc(s1_len + s2_len + 1);
if (s == NULL)
return NULL;
{
char* s_end = s;
s_end = mempcpy(s_end, s1, s1_len);
s_end = mempcpy(s_end, s2, s2_len);
*s_end = '\0';
}
return s;
}
Example usage:
#include <stdio.h>
int main() {
char* s = strdupcat("abc", "def");
if (s == NULL) {
perror("Can't concatenate");
return EXIT_FAILURE;
}
puts(s);
free(s);
return EXIT_SUCCESS;
}
This function is used similarly to strdup.
DESCRIPTION
The strdupcat() function returns a pointer to a new string which is a duplicate of the string s1 with a duplicate of string s2 appended. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
RETURN VALUE
The strdupcat() function returns a pointer to the duplicated string, or NULL if insufficient memory was available.
ERRORS
ENOMEM Insufficient memory available to allocate the new string.
You can use strerror or perror to obtain an error message when strdupcat() returns NULL.
Here's a version that accepts an arbitrary number of arguments:
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
char* strdupcatmany(int dummy, ...) {
#define strdupcatmany(...) strdupcatmany(0, __VA_ARGS__, NULL)
size_t len = 0;
char* s;
char* s_dst;
const char* s_src;
va_list ap;
va_start(ap, dummy);
while (1) {
s_src = va_arg(ap, const char*);
if (s_src == NULL)
break;
len += strlen(s_src);
}
va_end(ap);
s = malloc(len + 1);
if (s == NULL)
return NULL;
s_dst = s;
va_start(ap, dummy);
while (1) {
s_src = va_arg(ap, const char*);
if (s_src == NULL)
break;
s_dst = stpcpy(s_dst, s_src);
}
va_end(ap);
*s_dst = '\0';
return s;
}
For example,
#include <stdio.h>
int main() {
char* s = strdupcatmany("abc", "def", "ghi");
if (s == NULL) {
perror("Can't concatenate");
return EXIT_FAILURE;
}
puts(s);
free(s);
return EXIT_SUCCESS;
}
Note: I don't know how portable __VA_ARGS__ args is.
I'm trying generate a rsa public key from a modulus type char[], and I now the exponent is RSA_F4(65537);
But when I'm trying generate my public key using this values for "n" and "e", the RSA_public_encrypt, return -1;
Thanks!
My code:
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <crypt.h>
#include <iostream>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/opensslconf.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/rc4.h>
using namespace std;
int main(void)
{
//modulus in format char hex;
char key[] = "C0E7FC730EB5CF85B040EC25DAEF288912641889AD651B3707CFED9FC5A1D3F6C40062AD46E3B3C3E21D4E71CC4800C80226D453242AEB2F86D748B41DDF35FD";
char palavra[] = "teste";
char crip[512];
int ret;
RSA * pubkey = RSA_new();
BIGNUM * modul = BN_new();
BIGNUM * expon = BN_new();
BN_hex2bn(&modul, (const char *) key);
BN_hex2bn(&expon, "010001");
cout << "N KEY: " << BN_bn2hex(modul) << endl;
cout << "E KEY: " << BN_bn2hex(expon) << endl;
pubkey->n = modul;
pubkey->e = expon;
cout << "N PUB KEY: " << BN_bn2hex(pubkey->n) << endl;
cout << "E PUB KEY: " << BN_bn2hex(pubkey->e) << endl;
if (RSA_public_encrypt(strlen((const char *) palavra), (const unsigned char *) palavra, (unsigned char *) crip, pubkey, RSA_PKCS1_PADDING ))
{
printf("ERRO encrypt\n");
}
else
{
printf("SUC encrypt\n");
}
return 0;
}
You probably want something that looks more like:
RSA *pubkey = RSA_new();
int len = BN_hex2bn(&pubkey->n, (const char *)p);
if (len == 0 || p[len])
fprintf(stderr, "'%s' does not appear to be a valid modulus\n", p);
BN_hex2bn(&pubkey->e, "010001");
edit
Your code works fine, except for the error check. RSA_public_encrypt returns the size of the ciphertext on success, not 0, so to make the code above work, add a <= 0 test to if line:
if (RSA_public_encrypt(....) <= 0)
Here is some C code, that does the trick:
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
// cheating, .. ignoring deprecation warnings
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
unsigned char *base64_decode(const char* base64data, int* len) {
BIO *b64, *bmem;
size_t length = strlen(base64data);
unsigned char *buffer = (unsigned char *)malloc(length);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf((void*)base64data, length);
bmem = BIO_push(b64, bmem);
*len = BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
BIGNUM* bignum_base64_decode(const char* base64bignum) {
BIGNUM* bn = NULL;
int len;
unsigned char* data = base64_decode(base64bignum, &len);
if (len) {
bn = BN_bin2bn(data, len, NULL);
}
free(data);
return bn;
}
EVP_PKEY* RSA_fromBase64(const char* modulus_b64, const char* exp_b64) {
BIGNUM *n = bignum_base64_decode(modulus_b64);
BIGNUM *e = bignum_base64_decode(exp_b64);
if (!n) printf("Invalid encoding for modulus\n");
if (!e) printf("Invalid encoding for public exponent\n");
if (e && n) {
EVP_PKEY* pRsaKey = EVP_PKEY_new();
RSA* rsa = RSA_new();
rsa->e = e;
rsa->n = n;
EVP_PKEY_assign_RSA(pRsaKey, rsa);
return pRsaKey;
} else {
if (n) BN_free(n);
if (e) BN_free(e);
return NULL;
}
}
void assert_syntax(int argc, char** argv) {
if (argc != 4) {
fprintf(stderr, "Description: %s takes a RSA public key modulus and exponent in base64 encoding and produces a public key file in PEM format.\n", argv[0]);
fprintf(stderr, "syntax: %s <modulus_base64> <exp_base64> <output_file>\n", argv[0]);
exit(1);
}
}
int main(int argc, char** argv) {
assert_syntax(argc, argv);
const char* modulus = argv[1];
const char* exp = argv[2];
const char* filename = argv[3];
EVP_PKEY* pkey = RSA_fromBase64(modulus, exp);
if (pkey == NULL) {
fprintf(stderr, "an error occurred :(\n");
return 2;
} else {
printf("success decoded into RSA public key\n");
FILE* file = fopen(filename, "w");
PEM_write_PUBKEY(file, pkey);
fflush(file);
fclose(file);
printf("written to file: %s\n", filename);
}
return 0;
}
See this link for further info: http://www.techper.net/2012/06/01/converting-rsa-public-key-modulus-and-exponent-into-pem-file/
if I have this function:
printAll(const char *message, ...)
{
va_list argptr = NULL;
va_start(argptr, message);
// todo: how to printf all the arguments in the message?
va_end(argptr);
}
Suppose I call the function like this:
printAll("My info: Value1 = %d, Value 2=%d", 1, 2);
In this line: // todo: how to printf all the arguments in the message?
How can I print them all in order to have:
My info: Value1 = 1, Value 2=2
You're looking for the vprintf() function which was designed to do exactly this:
vprintf(message, argptr);
The v*printf() family of functions work basically in the same way as their normal counterparts, except they take a va_list instead of varargs. They don't call va_end() for you, so the way you have it now is correct.
Here's a sketch of the general idea (though a finished version, has to deal with quite a few more things such as field width, precision, more conversions, etc.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
int my_vfprintf(FILE *file, char const *fmt, va_list arg) {
int int_temp;
char char_temp;
char *string_temp;
char ch;
int length = 0;
char buffer[512];
while ( ch = *fmt++) {
if ( '%' == ch ) {
switch (ch = *fmt++) {
/* %% - print out a single % */
case '%':
fputc('%', file);
length++;
break;
/* %c: print out a character */
case 'c':
char_temp = va_arg(arg, int);
fputc(char_temp, file);
length++;
break;
/* %s: print out a string */
case 's':
string_temp = va_arg(arg, char *);
fputs(string_temp, file);
length += strlen(string_temp);
break;
/* %d: print out an int */
case 'd':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 10);
fputs(buffer, file);
length += strlen(buffer);
break;
/* %x: print out an int in hex */
case 'x':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 16);
fputs(buffer, file);
length += strlen(buffer);
break;
}
}
else {
putc(ch, file);
length++;
}
}
return length;
}
int my_printf(char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(stdout, fmt, arg);
va_end(arg);
return length;
}
int my_fprintf(FILE *file, char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(file, fmt, arg);
va_end(arg);
return length;
}
#ifdef TEST
int main() {
my_printf("%s", "Some string");
return 0;
}
#endif
Here is a printAll() that will do exactly as you would like...
#ifdef __cplusplus
#include <cstring>
#include <cstdio>
#include <cstdarg>
using namespace std;
#else
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#endif
void printAll(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
const size_t MAX_LEN = 1023;
#ifdef __cplusplus
char msg[MAX_LEN+1] = {0};
#else
char msg[MAX_LEN+1];
for (int i = 0; i < MAX_LEN+1; i++)
{
msg[i] = 0;
}
#endif
vsnprintf(msg, MAX_LEN, fmt, ap);
printf("%s\n", msg);
va_end(ap);
}
int main() {
printAll("My info: Value1 = %d, Value 2=%d", 1, 2);
return 0;
}
My info: Value1 = 1, Value 2=2
I've been at this for some time now. I need a basic IRC Ping Pong function to return the the proper response when the IRC server pings. I changed the name of the function get() to something else and I'm still getting the error. I thought perhaps the function name get() was already defined in one of the includes or something else.
#include "stdafx.h"
#include "Ping_Pong.h"
#include <iostream>
#include <ws2tcpip.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApp theApp;
#define MT4_EXPFUNC __declspec(dllexport)
#pragma comment(lib, "Ws2_32.lib")
class MT4_EXPFUNC IRC {
private:
char buf[513];
char rbuf[513];
char sbuf[513];
char *tok;
int recv_bytes;
int irc_socket;
struct addrinfo hints;
struct addrinfo *results;
public:
char *nick, *user, *host, *chan, *type, *mesg;
int irc_connect(const char *host, const char *port, const char *nick);
void socket_err(const char* err_string);
//int join(const char *channel);
This is the name of the function in question
int __stdcall get();
char *check(const char* test_str);
char *pop_arg(char **save_ptr);
int init_comarg();
int say(const char *channel, const char *message);
int sayf(const char *channel, const char *message, ...);
int mode(const char *channel, const char *mode, char *target);
//void die();
};
And this is the function I'm having a problem with.
MT4_EXPFUNC int __stdcall IRC::get()
{
memset(rbuf, 0, 513);
recv_bytes = recv(irc_socket, rbuf, sizeof(rbuf), 0);
if (recv_bytes <= 0) {
return -1;
}
std::cout << rbuf;
// Auto-Respond to PING messages.
if (rbuf[0] == 'P' && rbuf[1] == 'I') {
tok = strtok(rbuf, "PING :");
sprintf(buf, "PONG %s", tok-1 );
send(irc_socket, buf, strlen(buf), 0);
std::cout << buf;
memset(buf, 0, 513);
}
if ( strstr(rbuf, "PRIVMSG")) {
memcpy(sbuf, rbuf, 513);
nick = strtok(sbuf, "!") + 1;
user = strtok(NULL, "#");
host = strtok(NULL, " ");
type = strtok(NULL, " ") - 1;
chan = strtok(NULL, " ");
mesg = strtok(NULL, ":");
}
return 1;
}
In the tutorial linked below, a .def file was suggested with the following code:
Library "Ping_Pong"
Export get
I removed the .def and it worked.
http://www.xpworx.com/metatrader-mql-articles/mql4-articles/create-your-own-metatrader-extension-dll.php