我正在编写C编译器,当我执行该switch语句时,一个约束使我很困惑。标准的 6.8.4.2p2节规定:
如果switch语句在标识符的范围内具有关联的大小写或默认标签,且标识符的类型可变,则整个switch语句应在该标识符的范围内。
带有脚注:
也就是说,声明要么在switch语句之前,要么在最后一个case或默认标签之后,该标签与包含该声明的块中的switch关联。
我真的不明白这个约束的含义。可以给我一个例子吗?
我想在我的课程中做一些线程注册,所以我决定为该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) 我想自定义一个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编译器,如果我解析这样的语句:
int i;
(i) = 1;
Run Code Online (Sandbox Code Playgroud)
我的编译器将报告一个错误,指出该错误(i)是一个右值,不应分配。
我检查了代码和规则,并在赋值表达式语义中发现了这一点:
赋值运算符的左值应为可修改的左值。
赋值表达式具有赋值后的左操作数的值,但不是左值。
在我的情况下,有两个赋值表达式:
(i) = 1和i括号中。因此,(i)应该是一个右值。
所以我的问题是:(i) = 1在此C标准中是否
非法?
c variable-assignment rvalue language-lawyer lvalue-to-rvalue
据我了解,当我们定义像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()];使用仅在运行时已知的大小.这是因为这个数组是在一个函数中定义的,它会在堆栈中分配数组,还是因为编译器可以在编译时找出大小是多少?
我正在编写一个内存管理库,需要显式调用析构函数,在我的设计中,我有一个指向对象的析构函数方法的指针,我编写如下代码:
void (*p)() = foo.~Foo;
Run Code Online (Sandbox Code Playgroud)
但是我得到了
错误:无法将类型为“ void(Foo ::)()noexcept”的类型的“ Foo ::〜Foo”转换为“ void(*)()”类型
我尝试了其他格式,void (Foo:: (*p))() noexcept = foo.~Foo;但失败了。
那么将析构函数分配给指针的正确方法是什么?
编辑: 在运行时,我的代码不知道堆中的类型,因此无法使用foo。〜Foo()。我需要一个适合所有析构函数的生成指针,这可能吗?
我对著名的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编译器上尝试过,它将无法编译。
所以有问题:
int test {} 正确的语法吗?我正在编写一个C编译器(以llvm作为后端)进行练习,并且遵循C11标准§6.2.4遵循规则。
在经历“对象的存储期限”部分时,一种情况使我感到困惑:
¶8具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(递归地包括所有包含的结构和联合的成员)是指具有自动存储期限和临时生存期的对象。它的生命周期从对表达式进行求值开始,并且其初始值为表达式的值。当包含完整表达式或完整声明符的求值结束时,其生存期结束。任何试图使用临时生存期修改对象的尝试都会导致未定义的行为。
我无法想象这种情况在讨论什么情况,尤其是数组成员部件(由于两个具有临时生存期的非左值,具有数组成员的结构与普通的非左值有什么区别吗?)有人可以给我代码吗?例子来说明这一点?
我有这样的代码:
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> …
据我所知,引用不能为空,但是当我运行这样的代码时:
#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()),它将无法编译。