【问题标题】:'C' - How to initialise a 32 bit integer value with a 32 bit float value?'C' - 如何用 32 位浮点值初始化 32 位整数值?
【发布时间】:2016-05-11 08:00:56
【问题描述】:

我正在尝试找到一种通用方法来使用参数值初始化数组或结构。当从数组或结构中使用参数时,我的函数将知道上下文,因此它将知道如何正确使用这些值。

要初始化数组/结构,我想做这样的事情:

const void *para[] = {  // General Purpose store for parameters
    "1234",             // Store string pointer
    (void *)1234,       // Store integer value
    (void *)12.34f,     // Store float value
};

字符串和整数参数类型都可以。浮点数不起作用,因为编译器没有将浮点数转换为 void 指针的方法。

我需要一种将浮点值转换为二进制表示的方法,以便可以将其视为 32 位无符号整数。这个可以吗?

我可以用 memcpy() 的蛮力解决这个问题,但这需要删除“const”。最终目标是将代码移植到具有有限 SRAM 的嵌入式 ARM 系统,因此数组/结构需要位于 ROM 中,因此需要由编译器初始化,而不是在运行时初始化。

【问题讨论】:

  • 您不应将void * 用作通用值类型。您的 memcpy 也可以工作:您的 const 适用于指向的内存,而不适用于 para 的元素。
  • 没有办法获得浮点literal的二进制表示。文字没有表示,只有对象(变量)有。
  • union 的(数组)是否适合您的需求?
  • 尝试复合文字 (c11):使用 float 和 void* 的联合,而不是 (void *)12.34f。类似((union { float f; void *p}){12.34f}).p.

标签: c casting


【解决方案1】:

使用结构而不是数组。

struct s_para { const char* a; int b; float c; } const para 
    = { "1234", 1234, 12.34f };

无需投射任何东西。

【讨论】:

  • 这是要走的路。我强烈建议将结构定义和变量定义分开。
  • 如果调用之间的类型组合不同,这将不起作用。
  • @KlasLindbäck 当然可以。使用不同的结构。这就是 for 的类型。如果需要,您可以将他们的地址转换为 void。
  • 我认为你没有抓住重点。它需要是通用的参数存储,因此任何值都可以存储任何类型。
  • “它需要是通用的参数存储”。 XY 问题?为什么需要通用的参数存储?如果你想要一个通用的pointer 指向参数存储,你可以有一个,它叫做void*。您可以传递(void*)&para 并根据需要将其转换为s_para*。
【解决方案2】:

您的通用数据数组包含 void 指针。指向未定义数据类型的指针。在许多系统上,指向大多数数据类型的指针大小不变,因此它指向什么并不重要。这只会在进行指针运算或访问内容时变得相关。你可能知道这一点。正如您所说,您的代码稍后会“知道”在什么上下文中使用哪个指针。到现在为止还挺好。假设我们有一个 32 位系统,因为它与您的数据类型匹配。

现在是你的类型:

  • 在编译期间字符串“1234”存储在文本部分。您的编译器会使用指向该内存部分的指针填充您的数据数组。
  • 使用整数,您将 1234 显式转换为 void 指针,告诉编译器:“嘿,这是一个指针,而不是整数”。只要您的整数和指针具有相同的长度或指针更大,这就会起作用。所以在我们的 32 位上是可以的。因此,您可以将值直接存储在通常存储指向某事物的指针的字段中。
  • 对于浮动,上面的机制不起作用。浮点数永远不能解释为内存地址,因此编译器会失败。

两个选项: 首先,将 int 和 float 存储在 text/constant 部分中,然后将指针放入我的数组中。但是我们必须事先存储这些值......(或者也许有一个花哨的技巧)。这适用于任何类型!:

static int v1 = 1234;
static float v2 = 12.34f;

const void *para[] = {  // General Purpose store for parameters
    "1234",             // Store string pointer
    &v1,                // Store integer value
    &v2,                // Store float value
};

其次,我在这里更喜欢的方式是使用联合。

union data_storage {
     const int t_int;
     const float t_float;
     const char *t_string;
};

const union data_storage params[] = {  // General Purpose store for parameters
    {.t_string = "1234"},           // Store string pointer
    {.t_int = 1234},                // Store integer value
    {.t_float = 12.34f},            // Store float value
};

我用它测试过

fprintf(stdout, "%s\n%i\n%f\n", params[0].t_string, params[1].t_int, params[2].t_float);

【讨论】:

  • 你用什么编译器测试过这个?剪切并粘贴到 VS2010 中它不会编译。有错别字吗?即'= ='和'data_storage'
  • 你是对的。有错别字- narf。我使用 gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4。现在纠正错别字!
  • 似乎 VS2010 不支持命名初始化程序,即它不像你的 gcc 那样符合 C99。不过它应该可以在我的 Keil ARM 上运行。
  • 指针在同一个系统上长度相同。不。根据C Standard:“指向void 的指针应具有与指向字符类型的指针相同的表示和对齐要求。类似地,指向兼容类型的合格或非合格版本的指针应具有相同的表示和对齐要求. ...所有指向联合类型的指针应具有相同的表示和对齐要求。指向其他类型的指针不必具有相同的表示或对齐要求。"
  • 谢谢。我将文本更新为关于指针长度的更模糊的回复。虽然它实际上并没有发生在我身上......并不是我真的检查过;)但这不会改变关于联合解决方案的任何事情,与其他方式相比,这在系统之间会更加安全。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
  • 2020-05-09
  • 2014-11-22
  • 2013-09-18
  • 2020-09-04
  • 2011-12-14
相关资源
最近更新 更多