Questions tagged «language-lawyer»

有关编程语言和环境的正式或权威规范的复杂性的问题。

7
关于C中的数组初始化的困惑
在C语言中,如果初始化这样的数组: int a[5] = {1,2}; 那么所有未显式初始化的数组元素将被隐式初始化为零。 但是,如果我这样初始化一个数组: int a[5]={a[2]=1}; printf("%d %d %d %d %d\n", a[0], a[1],a[2], a[3], a[4]); 输出: 1 0 1 0 0 我不明白,为什么要a[0]打印1而不是0?它是不确定的行为吗? 注意:这个问题是在采访中提出的。

4
空引用可能吗?
这段代码是否有效(和定义的行为)? int &nullReference = *(int*)0; 这两个g ++以及铛++编译它没有任何警告,即使使用-Wall,-Wextra,-std=c++98,-pedantic,-Weffc++... 当然,该引用实际上不是null,因为无法访问它(这意味着取消引用null指针),但是我们可以通过检查其地址来检查其是否为null: if( & nullReference == 0 ) // null reference

8
“否则”是单个关键字吗?
我是C ++的新手。我经常看到如下条件语句: if statement_0; else if statement_1; 题: 语法上,我可以将其else if视为单个关键字吗?还是实际上是if在外部的嵌套语句,else如下所示? if statement_0; else if statement_1;

7
具有名为main而不是main函数的全局变量的程序如何工作?
考虑以下程序: #include <iostream> int main = ( std::cout << "C++ is excellent!\n", 195 ); 使用Windows 7 OS上的g ++ 4.8.1(mingw64),程序可以编译并正常运行,并进行打印: C ++很棒! 到控制台。main似乎是全局变量而不是函数;没有功能,该程序如何执行main()?此代码是否符合C ++标准?程序的行为是否定义明确?我也使用了该-pedantic-errors选项,但是程序仍然可以编译并运行。

2
“ C ++编程语言”第4版第36.3.6节中的代码是否具有明确的行为?
在Bjarne Stroustrup的C ++编程语言第4版第36.3.6 STL类操作中,以下代码用作链接的示例: void f2() { std::string s = "but I have heard it works even if you don't believe in it" ; s.replace(0, 4, "" ).replace( s.find( "even" ), 4, "only" ) .replace( s.find( " don't" ), 6, "" ); assert( s == "I have heard it works …


8
高效的无符号到无符号转换避免实现定义的行为
我想定义一个函数,该函数接受unsigned intas作为参数,int并向该参数返回全模UINT_MAX + 1。 第一次尝试可能看起来像这样: int unsigned_to_signed(unsigned n) { return static_cast<int>(n); } 但是,正如任何语言律师所知,对于大于INT_MAX的值,从无符号转换为有符号是由实现定义的。 我要实现这一点,以便(a)仅依赖规范要求的行为;(b)它可以在任何现代机器和优化的编译器上编译为no-op。 至于奇异的机器...如果没有符号的int与未签名的int模UINT_MAX + 1一致,那么我想抛出一个异常。如果不止一个(我不确定这是可能的),那么我要最大的一个。 好,第二次尝试: int unsigned_to_signed(unsigned n) { int int_n = static_cast<int>(n); if (n == static_cast<unsigned>(int_n)) return int_n; // else do something long and complicated } 当我不使用典型的二进制补码系统时,我不太关心效率,因为我的拙见认为这不太可能。而且,如果我的代码成为2050年无处不在的符号幅度系统的瓶颈,那么我敢打赌,有人可以弄清楚这一点,然后对其进行优化。 现在,第二次尝试非常接近我想要的。尽管强制转换int为某些输入的实现定义,但是unsigned标准保证了强制转换为保留对UINT_MAX + 1取模的值。因此,条件条件确实会检查我想要的内容,并且在任何可能遇到的系统上,它都不会编译成任何东西。 但是...我仍然在int不首先检查它是否将调用实现定义的行为的情况下进行投射。在2050年的某个假设系统上,它可以做谁知道什么。所以说我要避免这种情况。 问题:我的“第三次尝试”应该是什么样的? 回顾一下,我想: 从unsigned int转换为signed int …

3
什么时候类型信息在C ++中向后流动?
我刚刚看了斯蒂芬·拉瓦维(Stephan T. Lavavej)在CppCon 2018“类模板参数推论”上的讲话,在某个时候他偶然说: 在C ++类型的信息中,信息几乎永远不会倒退…… 我不得不说“几乎”,因为只有一两种情况,可能更多但很少。 尽管试图弄清楚他可能指的是哪种情况,但我什么也没想出来。因此,问题是: 在哪种情况下,C ++ 17标准要求类型信息向后传播?

4
为什么(仅)某些编译器对相同的字符串文字使用相同的地址?
https://godbolt.org/z/cyBiWY 我可以'some'在MSVC生成的汇编代码中看到两个文字,但是只有一个带有clang和gcc。这导致代码执行的结果完全不同。 static const char *A = "some"; static const char *B = "some"; void f() { if (A == B) { throw "Hello, string merging!"; } } 谁能解释这些编译输出之间的区别和相似之处?为什么即使不要求优化,clang / gcc也会优化某些内容?这是某种不确定的行为吗? 我还注意到,如果将声明更改为以下所示,则clang / gcc / msvc根本不会"some"在汇编代码中保留任何声明。为什么行为不同? static const char A[] = "some"; static const char B[] = "some";

2
除运算符优先级外,什么时候附加括号什么时候起作用?
C ++中的括号在许多地方使用:例如,在函数调用和分组表达式中,以覆盖运算符优先级。除了非法的多余括号(例如在函数调用参数列表周围)之外,C ++的一个通用而非绝对规则是,多余的括号永远不会损害: 5.1主表达式[expr.prim] 5.1.1常规[expr.prim.general] 6带括号的表达式是一个主表达式,其类型和值与附带的表达式相同。括号的存在不影响表达式是否为左值。除非另有说明,否则带括号的表达式可以在与可以使用封闭表达式的上下文完全相同的上下文中使用,并且具有相同的含义。 问题:除了覆盖基本的运算符优先级以外,多余的括号还会在哪些上下文中更改C ++程序的含义? 注意:我认为指针到成员语法的限制(&qualified-id不带括号)不在范围内,因为它限制了语法,而不是允许两种具有不同含义的语法。同样,在预处理程序宏定义中使用括号也可以防止不必要的运算符优先级。

2
使用非静态数据成员的类内初始化和嵌套类构造函数时出错
以下代码非常简单,我希望它可以编译良好。 struct A { struct B { int i = 0; }; B b; A(const B& _b = B()) : b(_b) {} }; 我已经使用g ++ 4.7.2、4.8.1,clang ++ 3.2和3.3测试了此代码。除了此代码的g ++ 4.7.2 segfaults(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57770)之外,其他经过测试的编译器给出的错误消息也没有太多解释。 g ++ 4.8.1: test.cpp: In constructor ‘constexpr A::B::B()’: test.cpp:3:12: error: constructor required before non-static data member for ‘A::B::i’ has …

3
这是C ++ 11 for循环的已知陷阱吗?
让我们想象一下,我们有一个结构可以容纳带有某些成员函数的3个double: struct Vector { double x, y, z; // ... Vector &negate() { x = -x; y = -y; z = -z; return *this; } Vector &normalize() { double s = 1./sqrt(x*x+y*y+z*z); x *= s; y *= s; z *= s; return *this; } // ... }; 为了简化起见,这有点人为设计,但是我敢肯定您同意类似的代码已经存在。这些方法使您可以方便地进行链接,例如: Vector v …

3
什么时候私有构造函数不是私有构造函数?
假设我有一个类型,并且想将其默认构造函数设为私有。我写以下内容: class C { C() = default; }; int main() { C c; // error: C::C() is private within this context (g++) // error: calling a private constructor of class 'C' (clang++) // error C2248: 'C::C' cannot access private member declared in class 'C' (MSVC) auto c2 = C(); // …

8
可以将具有未定义行为的分支视为不可达并优化为死代码吗?
考虑以下语句: *((char*)NULL) = 0; //undefined behavior 它显然会调用未定义的行为。给定程序中存在这样的语句是否意味着整个程序是未定义的,或者行为仅在控制流命中该语句后才变为未定义? 如果用户从不输入数字,以下程序是否定义明确3? while (true) { int num = ReadNumberFromConsole(); if (num == 3) *((char*)NULL) = 0; //undefined behavior } 还是无论用户输入什么,都是完全不确定的行为? 另外,编译器可以假定未定义的行为永远不会在运行时执行吗?这将允许往后倒推: int num = ReadNumberFromConsole(); if (num == 3) { PrintToConsole(num); *((char*)NULL) = 0; //undefined behavior } 在这里,编译器可能会推断出万一num == 3我们总是调用未定义的行为。因此,这种情况必须是不可能的,并且不需要打印号码。整个if语句可以优化。根据标准是否允许这种向后推理?


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.