【问题标题】:Is it safe to scan a struct of N members of same type as an array?扫描与数组相同类型的 N 个成员的结构是否安全?
【发布时间】:2015-12-30 19:00:05
【问题描述】:

我有这个结构:

typedef struct V2f {
    float x, y; } V2f;

在我的机器(64 位 Lubuntu 15.10)上,我可以使用此功能毫无问题地扫描它:

#include <stdbool.h>
#include <stdio.h>

bool scan_struct_as_arr(void *dst, int n, size_t sz, char *format) {
    for(int i = 0; i < n; ++i) {
        if(!scanf(format, (char *) dst + i * sz)) {
            fputs("Failed to scan struct as an array", stderr);
            return false; } }
    return true; }

这种行为在多大程度上是可移植的?为什么?

如果只使用大小为 4 或 8 的变量,是否可以信任此代码?

【问题讨论】:

  • 安全还是便携?你的问题是什么?两个都?它们并不完全相同。不可移植的构造可以是完全安全的。 (这里安全,那里不安全。)
  • 两者。它的安全性和便携性如何。
  • 对齐是实现定义的,所以可能会有填充字节。
  • 看起来像一个安全故障:传递未经检查的格式字符串,不使用const 限定符,依赖于特定的布局和字节序,疯狂地转换类型(自动类型检查有什么问题?)。如果某个同事给了我这样的代码,那就是认真讨论的时候了。
  • arm_neon.h 中定义的向量类型具有明确定义的结构并且(我相信)对于这种使用是安全的,因为它与数组等价物具有明确定义的关系。我想这也应该是 gcc 矢量扩展的情况。

标签: c arrays pointers struct scanf


【解决方案1】:

一般来说,这既不安全也不便携:

C.11 6.7.2.1 结构和联合说明符

  1. 结构或联合对象的每个非位域成员在定义的实现中对齐 适合其类型的方式。
  2. 在结构对象中,非位域成员和位域所在的单元 驻留的地址按照声明的顺序增加。 ...可能有未命名的 在结构对象内填充,但不在其开头。

给定的实现可能会决定,对于结构,每隔一个浮点数应该与前一个浮点数相距 16 位,而对于数组,它会使它们保持连续。

更便携的解决方案是只传递地址,可以是数组,也可以是变量参数:

bool scan_addr_array (void *addrs[], size_t N, const char *fmt);
bool scan_addr_va (const char *fmt, ... /* NULL terminated */);

【讨论】:

  • 但是浮点数是 32 位宽的,而不是 16 位宽的。所以没有填充,对吧?或者至少,99% 的设备没有填充?
  • 48 位机器,32 位浮点数
【解决方案2】:

不安全,不可移植:从struct V2f *void * 再到char * 的转换会调用未定义行为。

【讨论】:

  • 我以为每个指针类型都可以转换为char*?我更担心scanf 写信给char*
  • 虽然我同意这是一个糟糕的代码,但如果扫描的数据与原始指针的类型匹配,我不确定它是否真的是 UB(但我不知道正确的格式字符串看起来如何喜欢),你能详细说明吗? (没有讨论这个代码是不行的)
  • @cad:也许可以(我想是的,但是void 被引入到语言中,除其他外,因为转换问题)。问题是 scanf 内的 char * 访问 struct V2f 类型的对象。
  • 所以你的意思是我提到的scanf 通过char* 写入float
  • @cad:因为我会拒绝像 IRL 这样的代码,我实际上很好奇证明链,这是技术上 UB。我认为这甚至可能是技术上允许的。当涉及到void *char * 时,标准中的定义漏洞太多了。所以我尝试查看原始对象的类型以及scanf 实际读取的内容。这就是为什么我对给定struct 的格式字符串非常感兴趣的原因。这更像是6.5p6 的问题。
猜你喜欢
  • 2020-06-22
  • 2020-01-08
  • 2017-06-11
  • 1970-01-01
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多