【问题标题】:Convert integer to string with C++ compatible function for Matlab Coder使用 Matlab Coder 的 C++ 兼容函数将整数转换为字符串
【发布时间】:2015-10-13 09:34:24
【问题描述】:

我正在使用 Matlab Coder 将一些 Matlab 代码转换为 C++,但是在将整数转换为字符串时遇到了问题。

int2str() 不支持代码生成,所以我必须找到其他方法将整数转换为字符串。我试过用谷歌搜索它,但没有成功。这甚至可能吗?

【问题讨论】:

  • 是否支持num2str?是此类中最通用的函数。
  • num2str 也不支持。

标签: string matlab type-conversion matlab-coder


【解决方案1】:

这可以手动完成(虽然非常痛苦)

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

【讨论】:

  • 我认为您需要将while 条件更改为n>0
  • 次要,这会为有符号整数类型的intmin 打印不正确的字符串,因为abs(n) 将饱和。例如abs(intmin('int32')) 将饱和,以便打印-intmax('int32')。可以为intmin 添加一个检查,然后将一个检查添加到s(end)
【解决方案2】:

sprintf 是另一个非常基本的函数,因此它可能也适用于 C++:

x = int64(1948)
str = sprintf('%i',x)

也是int2str使用的底层函数。


根据这个comprehensive list of supported functions,正如Matt在cmets中指出的那样,不支持sprintf,这是令人惊讶的。但是有一个未记录的帮助函数(因此不在列表中)sprintfc,它似乎可以工作并且可以等效地使用:

str = sprintfc('%i',x)

【讨论】:

  • 我也是这么想的。在写答案之前,我检查了列表heresprintf 似乎不被支持。
  • sprintf 也不支持。
  • @ein123 未记录的sprintfc 怎么样 - 你能查一下吗?
  • sprintfc 实际上似乎有效。我想那是最顺利的解决方案。谢谢! @thewaywewalk
  • 其实我现在发现sprintfc 不起作用。出于某种原因,它一开始没有发出警告,但现在它发出了警告。所以我想你必须手动执行此操作。 @thewaywewalk
【解决方案3】:

我使用以下解决方法来启用 sprintf 以与 Matlab Coder 一起使用:

1) 创建以下名为“sprintf.m”的 m 文件,最好放在不在 Matlab 路径上的文件夹中:

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) 确保 sprintf 未通过 coder.extrinsic 指定为外部

3) 生成代码时指定包含新创建的“sprintf.m”的文件夹作为附加的包含目录。如果您使用codegen 功能,这可以通过-I 开关完成。如果您使用 Coder App,可以在“生成”选项卡的“更多设置 -> 自定义代码 -> 其他包含目录”下完成。

4) 从 int 转换为 string 如下:s=sprintf('%d',int32(n));

注意事项:

  • 每次您从生成的代码调用sprintf 时,指定的“sprintf.m”会隐藏内置的sprintf 函数并代替内置函数执行。通过将此文件放在不在 Matlab 路径上的文件夹中,您可以避免从其他要在 Matlab 中运行的代码调用它。 coder.target 调用还有助于导航回内置函数,以防它在正常的 Matlab 会话中或从 MEX 文件中调用。
  • 上面的代码将结果限制为 1023 个字符(最后需要一个终止零)。对 sprintf_s 的调用指示 C++ 编译器在结果超过此值时抛出运行时异常。这可以防止内存损坏,这种损坏通常只在很久以后才被发现,并且更难追溯到有问题的调用。可以根据您自己的要求修改此限制。
  • 在将数值类型传递给sprintf 之前,必须将它们转换为正确的类,例如转换为 int32 以匹配格式字符串中的 %d。将fprintf 与 Matlab Coder 一起使用时,此要求相同。但是,在fprintf 的情况下,Matlab Coder 会为您捕获类型错误。对于sprintf,C++ 编译器可能会失败,或者生成的字符串可能包含错误。
  • 字符串参数必须手动以 NULL 结尾才能在 C 调用中使用,因为 Matlab Coder 不会自动执行此操作(感谢 Ryan Livingston 指出这一点)。上面的代码确保格式字符串 f 以 NULL 结尾,但其他字符串参数的 NULL 结尾仍由调用函数负责。
  • 此代码已在 Windows 平台上使用 Visual Studio C++ 编译器和 Matlab R2016a (Matlab Coder 3.1) 进行了测试,但预计也可以在大多数其他环境中运行。

【讨论】:

  • 不要忘记对任何将是 C 字符串的参数进行空终止:cf = [f, 0]; coder.ceval(...,coder.rref(cf(1)));。 MATLAB Coder 生成的字符数组不是以空值结尾的。否则将导致生成的代码中出现未定义的行为。
【解决方案4】:

编辑:从 MATLAB R2018a 开始,MATLAB Coder 支持sprintf 进行代码生成。

R2018a 前答案

您还可以使用coder.ceval 调用C 运行时sprintfsnprintf。这样做的好处是也可以轻松支持浮点输入。您还可以通过调整格式字符串来根据需要更改格式。

假设你的编译器提供snprintf 可以使用:

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

请注意,您可能需要调整格式字符串以匹配您正在运行的硬件,因为这假定 long long 可用并将 64 位整数映射到它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多