Tag: 语言律师

用%p打印空指针是未定义的行为?

使用%p转换说明符打印空指针是未定义的行为吗? #include <stdio.h> int main(void) { void *p = NULL; printf("%p", p); return 0; } 这个问题适用于C标准,而不适用于C实现。

是“其他如果”一个关键字?

我是C ++新手。 我经常看到如下的条件语句: if statement_0; else if statement_1; 题: 在句法上 , else if作为单个关键字,我应该处理else if吗? 或者,它实际上是一个嵌套的if语句在外面else像下面? if statement_0; else if statement_1;

程序在3个主要的C ++编译器中被编译得不同。 哪一个是对的?

作为一个有趣的后续(虽然没有很大的实际重要性)到我以前的问题: 为什么C ++允许我们在声明variables时在括号中包围variables名? 我发现将括号中的声明与注入的类名称function组合在一起可能会导致令人惊讶的编译器行为结果。 看看下面的程序: #include <iostream> struct B { }; struct C { C (){ std::cout << "C" << '\n'; } C (B *) { std::cout << "C (B *)" << '\n';} }; B *y = nullptr; int main() { C::C (y); } 用g ++编译4.9.2给了我下面的编译错误: main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive] 它使用MSVC2013 […]

Double的“==”运算符的定义

出于某种原因,我偷偷进入Double类的.NET Framework源代码,发现==的声明是: public static bool operator ==(Double left, Double right) { return left == right; } 同样的逻辑适用于每个操作员。 这个定义是什么意思? 它是如何工作的? 为什么不创build一个无限recursion?

操作“false”是否真的被很好地定义?

C ++规范是如何定义的: 布尔参数的“小于”运算符的存在,如果是的话, 4个参数排列的结果? 换句话说,是由规范定义的以下操作的结果? false < false false < true true < false true < true 在我的设置(Centos 7,gcc 4.8.2)中,下面的代码吐出我所期望的(给出C代表false的历史logging为0,true为1): false < false = false false < true = true true < false = false true < true = false 虽然我很确定大多数(所有?)编译器会给出相同的输出,这是由C ++规范立法吗? 或者是一个模糊的,但符合规范的编译器允许决定true是不是错误? #include <iostream> const char * s(bool a) { return (a ? "true" […]

为什么f(i = -1,i = -1)未定义的行为?

我正在阅读评估违规的顺序 ,他们给我一个困惑的例子。 1)如果标量对象的副作用相对于同一个标量对象上的另一个副作用未被sorting,则行为是不确定的。 // snip f(i = -1, i = -1); // undefined behavior 在这种情况下, i是一个标量对象 ,这显然意味着 算术types(3.9.1),枚举types,指针types,成员types指针(3.9.2),std :: nullptr_t和这些types的cv限定版本(3.9.3)统称为标量types。 在这种情况下,我不明白这个陈述是如何含糊不清的。 在我看来,无论是第一个还是第二个参数先评估, i最终为-1 ,两个参数也是-1 。 有人可以澄清? UPDATE 我非常感谢所有的讨论。 到目前为止,我很喜欢@ harmic的回答,因为它暴露了定义这个陈述的陷阱和错综复杂的问题,尽pipe它乍看之下多么直截了当。 @ acheong87指出了使用引用时出现的一些问题,但是我认为这与这个问题的不确定副作用方面是正交的。 概要 由于这个问题引起了很大的关注,我将总结一下主要的观点和答案。 首先,请允许我进行一个小小的分析,指出“为什么”可以有密切相关但意义不同的含义,即“为什么”,“ 为什么 ”,“为了什么目的 ”。 我将把他们所说的“为什么”的那些含义的答案分组。 为什么导致 这里的主要答案来自保罗·德雷珀 ( Paul Draper) , 马丁·J ( Martin J)提供了一个类似但不是广泛的答案。 Paul Draper的答案归结为: 这是未定义的行为,因为它没有定义什么行为。 就解释C ++标准所说的问题而言,答案总的来说非常好。 它也解决了一些相关的UB案例,如f(++i, […]

C ++代码可以在C ++ 03和C ++ 11中都有效,但可以做不同的事情吗?

C ++代码是否可以符合C ++ 03标准和C ++ 11标准,但根据编译的标准做不同的事情?

通过void *投射,而不是使用reinterpret_cast

我正在读一本书,我发现不应该直接使用reinterpret_cast ,而是将其与static_cast结合使用void * T1 * p1=… void *pv=p1; T2 * p2= static_cast<T2*>(pv); 代替: T1 * p1=… T2 * p2= reinterpret_cast<T2*>(p1); 但是,我无法find一个解释为什么这比直接演员更好。 如果有人能给我一个解释或指出我的答案,我将非常感激。 提前致谢 ps我知道什么reinterpret_cast用于,但我从来没有看到这是用这种方式

高效的无符号签名转换避免了实现定义的行为

我想定义一个函数,将一个unsigned int作为参数,并返回一个int全等模UINT_MAX + 1的参数。 第一次尝试可能是这样的: int unsigned_to_signed(unsigned n) { return static_cast<int>(n); } 但正如任何语言律师所知道的,从无符号到大于INT_MAX的值被赋值是由实现定义的。 (a)只依赖规范规定的行为; 和(b)在任何现代机器上编译成优化编译器。 至于怪异的机器…如果没有签名整型全等模UINT_MAX + 1到无符号整型,让我们说我想抛出一个exception。 如果有不止一个(我不确定这是可能的),假设我想要最大的一个。 好的,第二次尝试: 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年无所不在的符号级系统的瓶颈,那么我敢打赌,有人可以弄清楚,然后优化它。 现在,这第二次尝试是非常接近我想要的。 尽pipe对于某些input来说,强制转换为int是实现定义的,但是由标准保证强制转换为unsigned ,以保留模数UINT_MAX + 1。 所以有条件的确会检查我想要的东西,而且在我可能遇到的任何系统上它都不会编译成任何东西。 但是…我仍然没有首先检查是否会调用实现定义的行为铸造为int 。 在2050年的某个假设系统中,它可以做谁知道什么。 所以我们说我想避免这种情况。 问题:我的“第三次尝试”应该是什么样子? […]

模板部分sorting – 为什么部分演绎在这里成功

考虑以下简单的问题(以模板问题为例): #include <iostream> template <typename T> struct identity; template <> struct identity<int> { using type = int; }; template<typename T> void bar(T, T ) { std::cout << "a\n"; } template<typename T> void bar(T, typename identity<T>::type) { std::cout << "b\n"; } int main () { bar(0, 0); } clang和gcc都在那里打印“a”。 根据[temp.deduct.partial]和[temp.func.order]中的规则,为了确定偏序,我们需要综合一些独特的types。 所以我们有两次尝试: +—+——————————-+——————————————-+ | | Parameters | […]