小编rea*_*esk的帖子

C标准中对可变修改类型的switch语句约束的说明

我正在编写C编译器,当我执行该switch语句时,一个约束使我很困惑。标准的 6.8.4.2p2节规定:

如果switch语句在标识符的范围内具有关联的大小写或默认标签,且标识符的类型可变,则整个switch语句应在该标识符的范围内。

带有脚注:

也就是说,声明要么在switch语句之前,要么在最后一个case或默认标签之后,该标签与包含该声明的块中的switch关联。

我真的不明白这个约束的含义。可以给我一个例子吗?

c label goto declaration switch-statement

13
推荐指数
1
解决办法
336
查看次数

我的编译器是否忽略了我未使用的静态thread_local类成员?

我想在我的课程中做一些线程注册,所以我决定为该thread_local功能添加一个检查:

#include <iostream>
#include <thread>

class Foo {
 public:
  Foo() {
    std::cout << "Foo()" << std::endl;
  }
  ~Foo() {
    std::cout << "~Foo()" << std::endl;
  }
};

class Bar {
 public:
  Bar() {
    std::cout << "Bar()" << std::endl;
    //foo;
  }
  ~Bar() {
    std::cout << "~Bar()" << std::endl;
  }
 private:
  static thread_local Foo foo;
};

thread_local Foo Bar::foo;

void worker() {
  {
    std::cout << "enter block" << std::endl;
    Bar bar1;
    Bar bar2;
    std::cout << "exit block" << std::endl;
  }
} …
Run Code Online (Sandbox Code Playgroud)

c++ compiler-optimization thread-local-storage

10
推荐指数
1
解决办法
128
查看次数

覆盖函数的异常规范比基本版本更宽松

我想自定义一个Exception类,这里是代码:

class TestException : std::exception{
  public:
  const char *what() const override {
    return "TestException";
  }
};
Run Code Online (Sandbox Code Playgroud)

我使用Clion和IDE给我一个警告what():exception specification of overriding function is more lax than base version

但是,如果我使用gcc构建代码,则不会发出警告.我使用的是c ++ 14,gcc 6.5.0

任何人都可以帮助解释警告意味着什么,我可以忽略它吗?

c++ exception c++14

9
推荐指数
2
解决办法
2083
查看次数

在标准C中,(i)= 1是否非法?

我正在编写遵循此标准的C编译器,如果我解析这样的语句:

int i;
(i) = 1;
Run Code Online (Sandbox Code Playgroud)

我的编译器将报告一个错误,指出该错误(i)是一个右值,不应分配。

我检查了代码和规则,并在赋值表达式语义中发现了这一点:

赋值运算符的左值应为可修改的左值。

赋值表达式具有赋值后的左操作数的值,但不是左值。

在我的情况下,有两个赋值表达式: (i) = 1i括号中。因此,(i)应该是一个右值。

所以我的问题是:(i) = 1在此C标准中是否 非法?

c variable-assignment rvalue language-lawyer lvalue-to-rvalue

8
推荐指数
2
解决办法
173
查看次数

定义具有不确定大小的数组

据我了解,当我们定义像const char argv[SIZE];"SIZE" 这样的数组时,必须是编译时已知的数字.

但最近我读了AOSP代码,发现了这个:http://androidxref.com/5.1.1_r6/xref/system/netd/server/NetdConstants.cpp#70

static int execIptables(IptablesTarget target, bool silent, va_list args) {
    /* Read arguments from incoming va_list; we expect the list to be NULL terminated. */
    std::list<const char*> argsList;
    argsList.push_back(NULL);
    const char* arg;
    do {
        arg = va_arg(args, const char *);
        argsList.push_back(arg);
    } while (arg);

    int i = 0;
    const char* argv[argsList.size()];
    ...
Run Code Online (Sandbox Code Playgroud)

似乎const char* argv[argsList.size()];使用仅在运行时已知的大小.这是因为这个数组是在一个函数中定义的,它会在堆栈中分配数组,还是因为编译器可以在编译时找出大小是多少?

c++ arrays

7
推荐指数
1
解决办法
452
查看次数

如何为指针分配析构函数?

我正在编写一个内存管理库,需要显式调用析构函数,在我的设计中,我有一个指向对象的析构函数方法的指针,我编写如下代码:

void (*p)() = foo.~Foo;
Run Code Online (Sandbox Code Playgroud)

但是我得到了

错误:无法将类型为“ void(Foo ::)()noexcept”的类型的“ Foo ::〜Foo”转换为“ void(*)()”类型

我尝试了其他格式,void (Foo:: (*p))() noexcept = foo.~Foo;但失败了。

那么将析构函数分配给指针的正确方法是什么?

编辑: 在运行时,我的代码不知道堆中的类型,因此无法使用foo。〜Foo()。我需要一个适合所有析构函数的生成指针,这可能吗?

c++

7
推荐指数
1
解决办法
147
查看次数

为什么“ int test {}”是C语言BNF中的函数定义

我对著名的Backus-Naur形式的C语法感兴趣并且研究了一段时间,令我感到困惑的是,某些语法在我看来错了,但根据BNF却被认为是正确的。

例如,int test {}这是什么?我认为这在C语言中是一种错误的语法,但事实是BNF认为这是一个函数定义:

int -> type_const -> type_spec -> decl_specs
test-> id -> direct_declarator -> declarator
'{' '}' -> compound_stat
decl_specs declarator compound_stat -> function_definition
Run Code Online (Sandbox Code Playgroud)

我用bison尝试过,它认为输入int test {}是正确的形式,但是我在C编译器上尝试过,它将无法编译。

所以有问题:

  1. int test {} 正确的语法吗?
  2. 如果语法正确,那是什么意思?为什么编译器无法识别它?
  3. 如果语法错误,我可以说BNF不严格吗?这是否意味着现代C编译器不坚持使用此BNF?

c parsing lalr bnf glr

6
推荐指数
1
解决办法
296
查看次数

C标准中使用寿命规则的说明

我正在编写一个C编译器(以llvm作为后端)进行练习,并且遵循C11标准§6.2.4遵循规则。

在经历“对象的存储期限”部分时,一种情况使我感到困惑:

¶8具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(递归地包括所有包含的结构和联合的成员)是指具有自动存储期限和临时生存期的对象。它的生命周期从对表达式进行求值开始,并且其初始值为表达式的值。当包含完整表达式或完整声明符的求值结束时,其生存期结束。任何试图使用临时生存期修改对象的尝试都会导致未定义的行为。

我无法想象这种情况在讨论什么情况,尤其是数组成员部件(由于两个具有临时生存期的非左值,具有数组成员的结构与普通的非左值有什么区别吗?)有人可以给我代码吗?例子来说明这一点?

c compiler-construction

6
推荐指数
2
解决办法
596
查看次数

如何专门针对特定类型的模板类方法?

我有这样的代码:

class Bar {
 public:
  void print() {
    std::cout << "bar\n";
  }
};

template<typename T>
class Foo {
 public:
  template <typename std::enable_if<std::is_base_of<T,Bar>::value,T>::type>
  void print() {
    t.print();
  }

 template <typename>
  void print() {
    std::cout << t << std::endl;
  }
 private:
  T t;
};

int main() {
//  Foo<int> foo1;
  Foo<Bar> foo2;
  foo2.print();
}
Run Code Online (Sandbox Code Playgroud)

这段代码的目的是:如果T ta是Bar或的子类Bar,则foo.print()推导为void print() {t.print();},否则推导为void print() {std::cout << t << std::endl;},但是事情没有按我预期的那样进行。编译器错误:

“非类型模板参数不能具有类型'typename std :: enable_if :: value,Bar> …

c++ compiler-errors sfinae template-specialization c++11

6
推荐指数
1
解决办法
144
查看次数

const std :: string&s = nullptr如何作为可选参数

据我所知,引用不能为空,但是当我运行这样的代码时:

#include <iostream>
#include <string>

void test(int i, const std::string& s = nullptr) {
  std::cout << i << " " << s << std::endl;
}

int main() {
  test(1, "test");
  test(2);
}
Run Code Online (Sandbox Code Playgroud)

可选参数s可以为null,并生成代码。此外,test(2)运行时,程序将引发异常,而不是打印一些随机字符串。

当我更改s为int之类的基本类型时,它无法编译,因此我认为魔术仍然保留在字符串类中,但是如何?

而且,如何检查是否s为null?如果我使用if(s==nullptr)if(s.empty()),它将无法编译。

c++ reference initializer stdstring nullptr

5
推荐指数
1
解决办法
214
查看次数