Reputation: 63
I'm using Matlab Coder to convert some Matlab code to C++, however I'm having trouble converting intergers to strings.
int2str()
is not supported for code generation, so I must find some other way to convert ints to strings. I've tried googling it, without success. Is this even possible?
Upvotes: 6
Views: 3192
Reputation: 1928
Edit: As of MATLAB R2018a, sprintf
is supported for code generation by MATLAB Coder.
Pre R2018a Answer
You could also call the C runtime sprintf
or snprintf
using coder.ceval
. This has the benefit of making supporting floating point inputs easy as well. You can also change the formatting as desired by tweaking the format string.
Supposing that your compiler provides snprintf
one could use:
function s = cint2str(x)
%#codegen
if coder.target('MATLAB')
s = int2str(x);
else
coder.cinclude('<stdio.h>');
assert(isfloat(x) || isinteger(x), 'x must be a float or an integer');
assert(x == floor(x) && isfinite(x), 'x must be a finite integer value');
if isinteger(x)
switch class(x)
% Set up for Win64, change to match your target
case {'int8','int16','int32'}
fmt = '%d';
case 'int64'
fmt = '%lld';
case {'uint8','uint16','uint32'}
fmt = '%u';
otherwise
fmt = '%llu';
end
else
fmt = '%.0f';
end
% NULL-terminate for C
cfmt = [fmt, 0];
% Set up external C types
nt = coder.opaque('int','0');
szt = coder.opaque('size_t','0');
NULL = coder.opaque('char*','NULL');
% Query length
nt = coder.ceval('snprintf',NULL,szt,coder.rref(cfmt),x);
n = cast(nt,'int32');
ns = n+1; % +1 for trailing null
% Allocate and format
s = coder.nullcopy(blanks(ns));
nt = coder.ceval('snprintf',coder.ref(s),cast(ns,'like',szt),coder.rref(cfmt),x);
assert(cast(nt,'int32') == n, 'Failed to format string');
end
Note that you'll possibly need to tweak the format string to match the hardware on which you're running since this assumes that long long
is available and maps 64-bit integers to it.
Upvotes: 2
Reputation: 1404
I use the following workaround to enable sprintf
for general use with Matlab Coder:
1) Create the following m-file named "sprintf.m", preferably in a folder NOT on your Matlab path:
function s = sprintf(f, varargin)
if (coder.target('MATLAB'))
s = builtin('sprintf',f,varargin{:});
elseif (coder.target('MEX'))
s = builtin('sprintf',f,varargin{:});
else
coder.cinclude('stdio.h');
s = char(zeros(1024,1));
cf = [f,0]; % NULL-terminated string for use in C
coder.ceval('sprintf_s', coder.ref(s(1)), int32(1024), coder.rref(cf(1)), varargin{:});
end
2) Ensure that sprintf
is not specified as extrinsic via coder.extrinsic
3) Specify the folder containing the newly created "sprintf.m" as additional include directory when generating code. If you use the codegen
function, this can be done via the -I
switch. If you use the Coder App, this can be done under "More Settings -> Custom Code -> Additional include directories" from the "Generate" tab.
4) Convert from int to string as follows: s=sprintf('%d',int32(n));
Notes:
sprintf
function and executes instead of the built-in function every time you call sprintf
from generated code. By placing this file in a folder that is not on the Matlab path, you avoid calling it from other code made to run in Matlab. The coder.target
call also helps to navigate back to the built-in function in case this gets called in a normal Matlab session or from a MEX file.sprintf_s
instructs the C++ compiler to throw a runtime exception if the result exceeds this value. This prevents memory corruption that is often only caught much later and is harder to trace back to the offending call. This limit can be modified to your own requirements.sprintf
, e.g. cast to int32
to match a %d
in the format string. This requirement is the same when using fprintf
with Matlab Coder. However, in the fprintf
case, Matlab Coder catches type errors for you. For sprintf
, the C++ compiler may fail or the resulting string may contain errors.f
is NULL-terminated, but NULL-termination of other string arguments remains the responsibility of the calling function.Upvotes: 2
Reputation: 25232
sprintf
is another very basic function, so it possibly works in C++ as well:
x = int64(1948)
str = sprintf('%i',x)
It is also the underlying function used by int2str
.
According to this comprehensive list of supported functions, as pointed out by Matt in the comments, sprintf
is not supported, which is surprising. However there is the undocumented helper function (therefore not in the list) sprintfc
which seems to work and can be used equivalently:
str = sprintfc('%i',x)
Upvotes: 7
Reputation: 114966
This can be done manually (very painful, though)
function s = thePainfulInt2Str( n )
s = '';
is_pos = n > 0; % //save sign
n = abs(n); %// work with positive
while n > 0
c = mod( n, 10 ); % get current character
s = [uint8(c+'0'),s]; %// add the character
n = ( n - c ) / 10; %// "chop" it off and continue
end
if ~is_pos
s = ['-',s]; %// add the sign
end
Upvotes: 8