Problem converting Matlab code to C standalone executable using Matlab Coder

Hello, I am trying to convert a very simple Matlab program (connect two input strings together) to a C standalone executable using Matlab Coder.
The m file I have is:
function r = connect(a,b) %#codegen
assert(isa(a,'char'));
assert(isa(b,'char'));
r = [a,b];
The main.c I have is:
#include <stdio.h>
#include <stdlib.h>
#include "connect.h"
#include "connect_initialize.h"
#include "connect_terminate.h"
int main(int argc, char *argv[])
{
connect_initialize();
printf("Result is %s\n", connect(argv[1],argv[2]));
connect_terminate();
return 0;
}
The error message I got is:
26 C:\C\connect\main.c(16) : warning C4047: 'function' : 'char_T' differs in levels of indirection from 'char *'
27 C:\C\connect\main.c(16) : warning C4024: 'connect' : different types for formal and actual parameter 1
28 C:\C\connect\main.c(16) : warning C4047: 'function' : 'char_T' differs in levels of indirection from 'char *'
29 C:\C\connect\main.c(16) : warning C4024: 'connect' : different types for formal and actual parameter 2
I'd really appreciate it if somebody can give me a hint. Thanks.

3 个评论

What does connect.h give as being the function signature for connect()? I suspect you will find that it is not expecting char* such as you will get from argv[1] and argv[2]
Hi Walter, thanks for the comment. The connect.h Matlab generated automatically is:
#ifndef __CONNECT_H__
#define __CONNECT_H__
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rtwtypes.h"
#include "connect_types.h"
extern void connect(char_T a, char_T b, char_T r[2]);
#endif
Did you mean the difference between char* and char_T? I also found this in rtwtypes.h:
typedef char char_T;
typedef char_T byte_T;
This might be the problem, but I don't think I understand C well enough to solve it. Could someone please point me the direction? Thanks.
I am also facing a problem while matlab to c conversion. I am working on ECG Analysis using Pan-Tompkins Algorithm I have a function defined as function [ ecg_m,qrs_amp_raw,qrs_i_raw,delay]= pan_tompkin(ecg,fs,gr) but after converting to c using matlab coder I am getting a function void pan_e(const emxArray_real_T *ecg, real_T fs, real_T gr, emxArray_real_T *ecg_m, real_T *delay)
and there is no a mention of qrs_amp_raw,qrs_i_raw which are mainly needed for further processing. Can someone suggest why this problem is occurring?

请先登录,再进行评论。

 采纳的回答

I think you will find this MATLAB Coder demo useful. To be able to pass in a char buffer, I believe you also need to assert on the length:
function r = connect(a,b) %#codegen
assert(isa(a,'char'));
assert(size(a, 1) <= 1024);
assert(isa(b,'char'));
assert(size(b, 1) <= 1024);
r = [a,b];
Note that the generated prototype also expects the length of the strings to be passed in:
extern void myconnect(const char_T a_data[1024], const int32_T a_size[1], const char_T b_data[1024], const int32_T b_size[1], char_T r_data[2048], int32_T r_size[2]);

8 个评论

Thank you very much, Kaustubha. This worked like a charm. Just a follow-up question, how do people usually handle matrix inputs as the str2num function is not supported by the Coder? I guess we will have to code our own?
Hank: Are you generating an executable from MATLAB Coder? If you need to pass in non-scalars, it might be better to generate a library that you can call from your own driver application which passes in the matrix values.
Walter, I need to convert input string to matrix, so I think sprintf would not work in this case.
Kaustubha, the exe will be deployed on a webserver and will be executed in a PHP script using command line. So I think I will have to parse the string input into matrix for the Matlab function anyway.
Sorry, misread. sscanf() is likely to be supported by the code generator.
Well that's a pain! No input functions at all, and the only output function is disp(). You are probably going to have to use coder.ceval()
Yeah, luckily disp() is sufficient for output, but it seems I will have to write some code for input conversion.

请先登录,再进行评论。

更多回答(1 个)

That C function signature corresponds to passing a single character to "a" and a single character to "b" and (I think) passing in a pointer to an array of exactly 2 characters to write "r" into.
Note: C expects "strings" to be null terminated, and so a C string with 2 usable characters would need 3 positions, the third for the 0 that terminates it. But it is not an error to construct a character array with only exactly 2 non-zero characters, as long as you do not treat it as a string. But in that code, you do try to treat it as a string, as you want to pass the result directly to printf(). One problem with that -- the function does not return anything and instead writes into an address you pass in in the third parameter.
I do not know why the code is expecting single characters instead of character arrays -- the assert() you are using would normally be suitable for character arrays. You probably need to do something different to alert codegen that you are not working with scalars. I speculate that you will need to initialize r to an array that is the maximum size of the string you will return.

15 个评论

Hi Walter, thanks again. You mentioned: "That C function signature corresponds to passing a single character to "a" and a single character to "b" and (I think) passing in a pointer to an array of exactly 2 characters to write "r" into." In that case should I expect this to work? (It did not and gave "'char_T' differs in levels of indirection from 'char [2]'")
int main(int argc, char *argv[])
{
char string_a[2];
char string_b[2];
char string_c[3];
connect_initialize();
strcpy(string_a, argv[1]);
strcpy(string_b, argv[2]);
strcpy(string_c,connect(string_a,string_b));
printf("Result is %s\n", string_c);
connect_terminate();
return 0;
}
It is ok because that was not what I wanted anyway. You suggested "you will need to initialize r to an array that is the maximum size of the string you will return." How should I do this, please?
Those strcpy() will not help. argv[1] and argv[2] are going to be pointers to C strings (null-terminated array of characters). Copying them won't make them any more valid. Copying only part of them might be useful in some cases, but if you were copying only part of them then you would use strncpy() instead of strcpy().
connect() shows up in the .h file as void, meaning it does not return anything. You cannot pass the result of connect() to anything. Instead you have to pass in the address of an array that will receive the result. You can then pass the address of the array into printf(). When you are sizing the array remember to take into account the terminating null that printf() will need. You can do that by passing connect() an array one longer than the maximum result it will write, and writing 0 into the final position after the call returns; or you can pass connect() an array exactly the right size, and then use strncpy() to copy it into a space one larger (and write 0 into the final position.)
To initialize r to the maximum size inside connect, experiment with
r = repmat(' ', 1, 20); %adjust the 20 to your needs
before you do the r = [a,b]
I tried different ways of doing what you suggested but still no success. I think I still don't quite understand pointers in C very well. How would you write the main function to make this work? I am thinking maybe I can learn from an example. Thanks.
#define Result_Size 5
char string_c[Result_Size];
connect(string_a,string_b, &string_c);
string_c[Result_Size - 1] = 0;
printf("Result is %s\n", string_c);
Still getting this error:
'char_T *' differs in levels of indirection from 'char (*)[5]'
Try
connect(string_a, string_b, string_c);
Depending on how the code generator handles the signal it is given through pre-allocation, you might need
connect(string_a[0], string_b[0], string_c);
Finally,
connect(string_a[0], string_b[0], string_c);
is working!
But obviously it only copies the first two characters of the two strings into string_c. How can I pass the two whole strings to "connect" instead of only two characters? Thanks again!
In the case where you use r = repmat(' ', 1, 20); as the first line of connect(), please show me the connect.h that is generated.
Matlab could not generate the executable with the "r=repmat('',1,20)" line present. The connect.h file is:
extern void connect(char_T a, char_T b, char_T r_data[8], int32_T r_sizes[2]);
So it seems I need to specify another argument in connect, the size of r?
Without that line, it can generate an exe for "connect(argv[1][0], argv[2][0], string_c);".
I am pasting my main.c here again:
#define Result_Size 20
char string_c[Result_Size];
int main(int argc, char *argv[])
{
connect_initialize();
connect(argv[1], argv[2], string_c);
string_c[Result_Size - 1] = 0;
printf("String_c is %s\n", string_c);
connect_terminate();
return 0;
}
I would be curious as to whether anything would change if you were to alter the assert() to be
assert(isa(a(10),'char'));
With the code as-is, I can see what should go into r_sizes, but I have not figured out yet why r_data came out as size 8, nor how to pass in multi-character strings.
(Note: I do not have the MATLAB Coder product, so I am back-engineering from the C code.)
assert(isa(a(10),'char'));
does not seem to be acceptable as Matlab throws a "Preconditioning: No class precondition specified for input 'a' of function 'connect'."
However, after I specify a fourth argument in connect, Matlab actually generated an exe, but when running it in command line, the result just does not make sense, for whatever inputs, it just gives something like "X^" or "Xd" alike.
Here are the latest main.c, connect.m and connect.h:
main.c:
#define Result_Size 40
char string_c[Result_Size];
int sizeArray[] = {1,20};
int main(int argc, char *argv[])
{
connect_initialize();
connect(argv[1], argv[2], string_c, sizeArray);
string_c[Result_Size - 1] = 0;
printf("string_a is %s, string_b is %s, string_c is %s\n", argv[1], argv[2], string_c);
connect_terminate();
return 0;
}
connect.m:
function r = connect(a,b) %#codegen
r = repmat('', 1, 20);
assert(isa(a,'char'));
assert(isa(b,'char'));
r = [a,b];
connect.h:
extern void connect(char_T a, char_T b, char_T r_data[2], int32_T r_sizes[2]);
Really appreciate your patience with me :)
It is still expecting single characters to pass into connect(), so argv[1][0] and argv[2][0] still.
I do not know how to convince it to accept strings at the moment.
Yeah, I also realized that. Too bad it seems no example in this documentation is about the char class: http://www.mathworks.com/help/toolbox/coder/ug/bq9_nbz.html
The reason I am doing this is because I need Matlab to convert an m file that takes a couple of matrix as inputs, I basically need to capture a couple of strings inputs at command line and convert them to matrix in either the m file or the main function. This is only one of my problem, after this one is solved, I still need to figure out a good way to convert comma and semi-colon separated strings to matrix, because the str2num function is not supported by Matlab Coder.
Anyway thank you for your time and patience!
Thanks again Walter. I wish I could accept two answers. Your answers helped a lot on the C side.

请先登录,再进行评论。

类别

帮助中心File Exchange 中查找有关 MATLAB Coder 的更多信息

产品

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by