Questions tagged «language-lawyer»

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

6
将2个字节转换为带符号的16位整数的正确方法是什么?
在这个答案中,zwol宣称: 从外部源将两个字节的数据转换为16位带符号整数的正确方法是使用如下辅助函数: #include <stdint.h> int16_t be16_to_cpu_signed(const uint8_t data[static 2]) { uint32_t val = (((uint32_t)data[0]) << 8) | (((uint32_t)data[1]) << 0); return ((int32_t) val) - 0x10000u; } int16_t le16_to_cpu_signed(const uint8_t data[static 2]) { uint32_t val = (((uint32_t)data[0]) << 0) | (((uint32_t)data[1]) << 8); return ((int32_t) val) - 0x10000u; } 上面的哪个函数合适,取决于数组包含小端还是大端表示。字节序不是这里要讨论的问题,我想知道为什么zwol0x10000u从uint32_t转换为的值中减去int32_t。 为什么这是正确的方法? …

2
为什么C的BNF语法允许使用init-declarator的空序列进行声明?
当查看C的BNF语法时,我认为声明的生产规则看起来像这样很奇怪(根据https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C%20in%20Backus-Naur%20form.htm): <declaration> ::= {<declaration-specifier>}+ {<init-declarator>}* ; 为什么要*为此使用量词(表示零次或多次出现)init-declarator?这允许诸如int;或之类的语句void;在语法上有效,即使它们在语义上无效。他们难道不是在生产规则中使用了+量词(一次或多次)*吗? 我尝试编译一个简单的程序,以查看编译器的输出,它所做的只是发出警告。 输入: int main(void) { int; } 输出: test.c: In function ‘main’: test.c:2:5: warning: useless type name in empty declaration int; ^~~

2
为什么不能保证std :: hash具有确定性?
此后,我们使用N4140(C ++ 14标准)。 根据第17.6.3.4节哈希要求, 返回的值应仅取决于k 程序持续时间内的参数。 [注意:因此,对于给定的程序执行,h(k)具有相同值的表达式的所有求值都会 k产生相同的结果。—尾注] 和§12年9月20日类模板哈希说 ... 实例hash<Key>应: (1.1)-满足哈希要求(17.6.3.4)... (1.2)-... 这意味着,如果重新启动程序,则哈希值value(即hash<decltype(value)>(value))可能采用不同的值。 但为什么?此限制不在C ++ 11标准中,而是在C ++ 14,C ++ 17和C ++ 20标准中。作为用户(不是STL开发人员),如果std::hash具有确定性,那将非常有用。实现确定性哈希函数有任何数学困难吗?但是我们日常使用的哈希函数(例如,不建议使用md5sum或更安全的函数sha256)都是确定性的。有效率问题吗?

1
类无法访问其自己的私有静态constexpr方法-lang虫?
这段代码不能在Clang(6,7,8,9,trunk)中进行编译,但是在GCC(7.1、8.1、9.1)中可以很好地进行编译: template<class T> struct TypeHolder { using type = T; }; template<int i> class Outer { private: template<class T> static constexpr auto compute_type() { if constexpr (i == 42) { return TypeHolder<bool>{}; } else { return TypeHolder<T>{}; } } public: template<class T> using TheType = typename decltype(Outer<i>::compute_type<T>())::type; }; int main() …

2
混淆二维数组时strlen的意外优化
这是我的代码: #include <string.h> #include <stdio.h> typedef char BUF[8]; typedef struct { BUF b[23]; } S; S s; int main() { int n; memcpy(&s, "1234567812345678", 17); n = strlen((char *)&s.b) / sizeof(BUF); printf("%d\n", n); n = strlen((char *)&s) / sizeof(BUF); printf("%d\n", n); } 使用gcc 8.3.0或8.2.1以及任何优化级别,但我期望的是-O0此输出。编译器决定将限制于,因此永远不能等于或超过被除以的值。0 22 2strlenb[0] 这是我的代码中的错误还是编译器中的错误? 标准中并未明确阐明这一点,但是我认为指针来源的主流解释是,对于任何对象X,代码(char *)&X都应生成一个可以迭代整个对象的指针X-即使X碰巧具有子数组作为内部结构。 (奖金问题,是否有gcc标志来关闭此特定优化?)

3
为什么选择这种转换运算符的重载?
考虑下面的代码。 struct any { template <typename T> operator T &&() const; template <typename T> operator T &() const; }; int main() { int a = any{}; } 此处,第二个转换运算符由过载分辨率选择。为什么? 据我了解,这两个运算符分别推导为operator int &&() const和operator int &() const。两者都在可行的功能集中。通读[over.match.best]并没有帮助我弄清楚为什么后者更好。 为什么后一种功能比前一种更好?

3
是否可以通过const引用返回默认参数的值?
是否可以通过const引用返回默认参数的值,如以下示例所示: https://coliru.stacked-crooked.com/a/ff76e060a007723b #include <string> const std::string& foo(const std::string& s = std::string("")) { return s; } int main() { const std::string& s1 = foo(); std::string s2 = foo(); const std::string& s3 = foo("s"); std::string s4 = foo("s"); }

1
C语言中重叠对象的语义是什么?
考虑以下结构: struct s { int a, b; }; 通常为1,此结构的大小为8,对齐方式为4。 如果我们创建两个struct s对象(更准确地说,我们将两个这样的对象写入分配的存储区),而第二个对象与第一个对象重叠怎么办? char *storage = malloc(3 * sizeof(struct s)); struct s *o1 = (struct s *)storage; // offset 0 struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4 // now, o2 points half way into o1 *o1 …

3
允许编译器对局部volatile进行常量折叠吗?
考虑以下简单代码: void g(); void foo() { volatile bool x = false; if (x) g(); } https://godbolt.org/z/I2kBY7 您可以看到,也gcc没有clang优化对的潜在调用g。在我的理解中,这是正确的:抽象机器假定volatile变量随时可能更改(由于例如被硬件映射),因此将false初始化不断折叠到if检查中将是错误的。 但是MSVC g完全消除了对的调用(保留对文件的读写volatile!)。这是符合标准的行为吗? 背景:我有时会使用这种结构来即时打开/关闭调试输出:编译器必须始终从内存中读取值,因此在调试过程中更改变量/内存应相应地修改控制流。 。MSVC输出确实重新读取了该值,但忽略了该值(可能是由于不断折叠和/或消除了死代码),这当然违背了我的意图。 编辑: volatile此处讨论了对读写的消除:是否允许编译器优化局部volatile变量?(感谢内森!)。我认为该标准非常明确,即必须进行那些读写操作。但是,该讨论并未涵盖编译器将这些读取结果视为理所当然并基于此进行优化是否合法。我想这是标准中未指定的/未指定的,但是如果有人证明我做错了,我会很高兴。 我当然可以制作x一个非局部变量来避免该问题。这个问题更多是出于好奇。

2
内联在模块接口中的含义
考虑头文件: class T { private: int const ID; public: explicit T(int const ID_) noexcept : ID(ID_) {} int GetID() const noexcept { return ID; } }; 或者,或者: class T { private: int const ID; public: explicit T(int const ID_) noexcept; int GetID() const noexcept; }; inline T::T(int const ID_) noexcept …

3
C ++ 20概念:当template参数符合多个概念时,选择哪种模板专业化?
鉴于: #include <concepts> #include <iostream> template<class T> struct wrapper; template<std::signed_integral T> struct wrapper<T> { wrapper() = default; void print() { std::cout << "signed_integral" << std::endl; } }; template<std::integral T> struct wrapper<T> { wrapper() = default; void print() { std::cout << "integral" << std::endl; } }; int main() { wrapper<int> w; …

3
Lambda函数可变捕获从引用到全局变量的行为差异
我发现如果我使用lambda使用mutable关键字捕获对全局变量的引用,然后修改lambda函数中的值,则结果在编译器之间是不同的。 #include <stdio.h> #include <functional> int n = 100; std::function<int()> f() { int &m = n; return [m] () mutable -> int { m += 123; return m; }; } int main() { int x = n; int y = f()(); int z = n; printf("%d %d %d\n", x, y, …

1
在自己的初始化器中使用变量
C ++ 20标准草案的[basic.scope.pdecl] / 1在注释中具有以下(非规范性)示例(合并请求3580之前的部分引号,请参见此问题的答案): unsigned char x = x; x使用其自己的(不确定的)值初始化。 这实际上在C ++ 20中具有明确定义的行为吗? 通常T x = x;,由于在初始化完成之前x的值是不确定的,因此表单的自我初始化具有未定义的行为。评估不确定值通常会导致未定义的行为([basic.indent] / 2),但是[basic.indent] /2.3中有一个特定的例外,该例外允许直接unsigned char从unsigned char具有不确定值的左值初始化变量(导致使用不确定值进行初始化) )。 这本身并不会因此导致不确定的行为,但会为其他类型T不属于无符号窄字符类型或std::byte如int x = x;。这些注意事项同样适用于C ++ 17及之前的版本,另请参见底部的链接问题。 但是,即使对于unsigned char x = x;,当前草案的[basic.lifetime] / 7也表示: 类似地,使用不依赖于其值的glvalue的属性,在其生命周期开始之前已得到明确定义。该程序在以下情况下具有未定义的行为: glvalue用于访问对象,或者 [...] 这似乎暗示x示例中的值只能在其生命周期内使用。 [basic.lifetime] / 1说: [...] 类型为T的对象的生存期始于以下情况: [...]和 它的初始化(如果有的话)已经完成(包括真空初始化)([dcl.init]), [...] 因此,x仅在初始化完成后才开始生命周期。但是在引用的示例中,x在x初始化完成之前使用的值。因此,使用具有未定义的行为。 …


2
是POD类型完全等同于琐碎的标准布局类型吗?
在C ++ 20中,不赞成使用POD的概念,因为它是琐碎且标准的布局的无意义的合成特征。但是,C ++ 20草案中POD的定义并不完全是“琐碎的和标准布局”;实际上是: POD类是既是普通类又是标准布局类的类,并且不具有非POD类类型的非静态数据成员(或其数组)。POD类型是标量类型,POD类,此类数组或这些类型之一的cv限定版本。 换句话说,POD类型不仅是琐碎的而且是标准布局的,而且也是递归的。 该递归需求是否多余?换句话说,如果一个类型既是琐碎的又是标准布局,那么它是否也自动递归地变得琐碎又是标准布局?如果答案为“否”,那么标准布局,琐碎类型却无法成为POD的例子是什么?

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.