【问题标题】:cpp empty array declarationcpp 空数组声明
【发布时间】:2013-03-19 08:27:15
【问题描述】:

您好,我有以下测试代码,我对 cpp 感到困惑。

  1. 如果您在 library.h 中声明一个带有空元素子句的数组 .. 编译器会选择什么?它也不抱怨,我用的是 Cygwin。

  2. 在 library.cpp 中,我将值分配给两个元素,编译器是否假设一个包含一个元素的数组,而我将第二个元素写入数组范围之外?

图书馆.h

#ifndef LIBRARY_H
#define LIBRARY_H

class library {

public:
    void print();
    char a[];
};

#endif

库.cpp

#include <stdio.h>
#include "library.h"

void library::print() {
    a[0] = 'a';
    printf("1. element: %d\n", a[0]);
    a[1] = 'b';
    printf("2. element: %d\n", a[1]);
}

client.cpp

#include <stdio.h>
#include "library.h"

void execute();
library l;

int main() {
    l = library();
    l.print();
    return 0;
}

生成文件

OPTIONS=-Wall

all: main

run: main
        ./main.exe

main: client.o library.o
        g++ $(OPTIONS) -o main $^

library.o: library.cpp library.h
        g++ $(OPTIONS) -c $<

.cpp.o:
        g++ $(OPTIONS) -c $<

clean:
        rm -r *.o

【问题讨论】:

  • 如果你在 valgrind 下执行它会发生什么? :)

标签: c++


【解决方案1】:
  1. 没有称为 C/C++ 的语言,因此您的 Q 不能同时标记。
  2. 由于您使用的是类,您的程序只能是 C++ 而不是 C。

public:
     void print();
     char a[];

此代码在 C++ 中完全是非法的。 C++ 中的数组大小需要是正的编译时间常数。解决方法是替换为:

public:
      void print();
      std::string a;

注意声明,

char a[];

在 c99 中有效并且被称为不完整数组类型,C 标准保证a 可以存储至少一个char 类型的元素。这在 C++ 中无效。 C++ 标准不允许这些。仅仅因为两者是不同的语言。

【讨论】:

  • 当你把它变成一个字符串时,这个a[0]='a'; 不起作用。替换为a="ab",则可以在printf语句中以a[0]a[1]的身份访问
  • @balki:为什么是printf?为什么不std::cout
  • 声明char a[]在C++中也是合法的,也是一个不完整的数组类型。不同的是,在 C++ 中,all 类成员必须是完整类型;在 C98(但不是 C90)中,有一个特殊的例外情况,它允许结构的 last 元素是不完整的数组类型(对您可以对结果结构执行的操作有限制)。并且编译器为它保留任何内存;结构的大小就好像这个元素不存在一样(除非它增加了结构的对齐要求)。
  • @balki 您不能分配给它,因为它具有数组类型。 (在他的情况下,您也不能分配给数组成员,因为它们不存在。)
【解决方案2】:

首先,它不是合法的 C++。这是一个古老的 hack,C 只做 在 C98 中是合法的。基本思路是这样的struct只能 动态分配(使用malloc),但是你分配 之后的对象需要大量内存。所以你会做 类似malloc( sizeof( library ) + strlen( s ) + 1 )。 hack 用于避免额外分配。

使用此 hack 的类不能new 一起使用,也不 它可以是成员还是基类。 (它不能是 C,或者。)

你可以在 C++ 中模拟一下:

class Library
{
    //  ...
    char* buffer() { return reinterpret_cast<char*>( this + 1 );
    void* operator new( size_t n, size_t extra )
    {
        assert( n == sizeof( Library ) );
        return ::operator new( n + extra );
    }
};

但是请注意,与 C 解决方案不同的是,这存在以下风险: 对齐问题。它适用于字符类型,而且 如果班上的其他成员至少需要同样多的东西,就可以工作 对齐作为缓冲区类型,但否则可能会失败。 (这 g++ 中 std::basic_string 的实现使用它——并且 如果用double 实例化,会在某些机器上崩溃。)

【讨论】:

    【解决方案3】:

    空数组声明一个长度为零的数组。它在 C 中通过将结构 S 放置在大于 sizeof(S) 的内存区域中,然后使用数组访问剩余内存来使用:

    memory* ptr = malloc(sizeof(memory) + sizeof(char) * 10);
    // you can now manipulate ptr->a as an array of 10 elements
    

    这是一个在 C++ 中用处不大的技巧。只需使用 std::vector 代替。

    【讨论】:

    • 这也不是“把戏”。它被称为灵活数组成员,并记录在 C99 标准中,特别是 C99 §6.7.2.1-p18,正如 Armen 指出的那样,它对 C++ 来说是非标准的。
    【解决方案4】:

    它在 C 中通常称为struct hack。它使用了一种称为灵活数组成员的特性。

    然而,这不是任何 C++ 标准规范的一部分。看看this question

    请注意,观察到某事明显有效并不意味着您可以依赖它可靠地工作。如果行为未定义,从技术上讲,任何事情都可能发生。包括猛禽突然攻击。

    在 C++ 中,您可能会改用 std::vector&lt;char&gt;std::string

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-29
      • 2016-01-26
      • 2013-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-09
      相关资源
      最近更新 更多