Sizeof(float) 在 atmega2560 上给出错误的结果

sizeof(float) giving wrong result on atmega2560

本文关键字:出错 错误 结果 atmega2560 float Sizeof      更新时间:2023-10-16

我正在使用atmega2560控制器和avr-g++。我正在调试适用于我的 Ubuntu 18.04 主机(使用 g++ 编译时)但不适用于 atmega2560 的代码。我认为这可能是不同数据类型大小的问题,并使用此代码进行调查(也给出如下):

int integerType;
float floatType;
double doubleType;
char charType;
printf("Size of int: %ld bytesn",sizeof(integerType));
printf("Size of float: %ld bytesn",sizeof(floatType));
printf("Size of double: %ld bytesn",sizeof(doubleType));
printf("Size of char: %ld byten",sizeof(charType));

主机上的结果看起来不错,但 atmega2560 上的 avr-g++ 编译代码为不同的数据类型提供了野生大小:

G++:

Size of int: 4 bytes
Size of float: 4 bytes
Size of double: 8 bytes
Size of char: 1 byte

avr-g++:

Size of int: 2 bytes
Size of float: 41680900 bytes
Size of double: 43253764 bytes
Size of char: 44957697 byte

这是完全不现实的。这可能是什么原因呢?

更新

有人建议我尝试 %zu 而不是 %ld 来打印 sizeof(...) 的 std::size_t 输出。不幸的是,这不起作用,输出如下所示:

Size of int: Size of float: Size of double: Size of char: 

在 atmega2560 上,整数为 2 个字节。因此,每次对printf的调用都传递格式字符串,后跟一个 2 字节整数。

但是格式字符串指定%ld,这是一个 4 字节long整数;所以printf期望堆栈上有一个 4 字节的值。因此,它从堆栈中读取未被调用函数推送到那里的字节;这些字节可以具有任何值。

如果您用%lX以十六进制打印值,您将看到低位两个字节的预期大小。例如,416809000x027C0004,您可以在该0004中看到float的大小。027C实际上是随机噪声。

要解决此问题,请使用%d而不是%ld。这将适用于您的 Ubuntu 主机(使用 4 字节整数)和 atmega2560(使用 2 字节整数)。

也许更好的是使用%z,正如chux的答案中所解释的那样,以防sizeof的大小与int的大小不同。

sizeof返回一个size_t- 一些无符号类型。 使用*printf()时,请使用指定的匹配说明符"zu"'。

// printf("Size of float: %ld bytesn",sizeof(floatType));
// () not needed with an object
printf("Size of float: %zu bytesn", sizeof floatType);

如果代码使用旧版本,则转换为最广泛的可用类型是另一种选择:

// Assume unsigned long is widest
printf("Size of float: %lu bytesn", (unsigned long) sizeof floatType);

当然,如果预期的结果很小,代码可以使用unsigned

printf("Size of float: %u bytesn", (unsigned) sizeof floatType);

然而,既然这是C++,那么下面呢? @Bob__

cout << "Size of float: " << sizeof floatType << " bytes" << endl;

这是完全不现实的。这可能是什么原因呢?

原因是 avr-gcc/avr-g++ 将size_t实现为 2 字节类型,请参阅 avr-gcc ABI 中的类型布局,但您使用的是需要long int的打印修饰符%ld,这是 avr-g++ 中的 4 字节类型

什么将在主机AVR 上工作

  • 您可以强制转换 size_t 操作数,使其与 printf 操作数匹配,例如将%u(unsigned) sizeof(float)一起使用,或将%lu(unsigned long) sizeof(float)一起使用。

  • 在使用 GCC 时,有一些内置宏被定义为基本类型的大小,因此它们可以在预处理器指令(如#if)中使用。 为了显示它们,您可以运行1

    > echo "" | avr-g++ -xc++ - -E -dM | grep SIZEOF
    

    这将打印类似的东西

    #define __SIZEOF_INT__ 2
    #define __SIZEOF_POINTER__ 2
    #define __SIZEOF_FLOAT__ 4
    

    缺少的是__SIZEOF_CHAR__每个语言标准始终为 1

什么不适用于 avr-gcc

对像%zu这样的size_t使用打印修饰符将不起作用2,因为 AVR-LibC 没有实现z。此决定背后的原因是保持代码大小占用空间最小。

也不起作用的是使用像std::cout << sizeof(float) ...中的流,因为 GNU 工具中没有用于 AVR 的 libstdc++。


1说明:-E建议编译器只预处理源文件,-dM打印所有已定义宏的值。 源文件-,这意味着从标准输入读取,这是截至echo "" |的空文件。 选项-xc++指定要C++的语言,这是必需的,因为输入文件没有文件扩展名。

2例如,64 位类型也没有实现。 为了支持float,你需要一个支持它的扩展版本的vfprintf。 这通常通过-Wl,-u,vfprintf -lprintf_flt访问,因为默认版本的 printf(和 scanf)不支持float

相关文章: