标签: language-lawyer

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

我想定义一个带有unsigned intas参数的函数,并向参数返回一个int全等模UINT_MAX + 1.

第一次尝试可能如下所示:

int unsigned_to_signed(unsigned n)
{
    return static_cast<int>(n);
}
Run Code Online (Sandbox Code Playgroud)

但正如任何语言律师所知,从无符号转换为大于INT_MAX的已签名值是实现定义的.

我想实现这一点,以便(a)它只依赖于规范规定的行为; (b)它在任何现代机器上编译成无操作并优化编译器.

对于奇怪的机器......如果没有签名的int congruent将UINT_MAX + 1模数为unsigned int,那么假设我想抛出一个异常.如果有多个(我不确定这是否可能),那么就说我想要最大的一个.

好的,第二次尝试:

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
}
Run Code Online (Sandbox Code Playgroud)

当我不是一个典型的二元补充系统时,我并不太关心效率,因为我认为不太可能.如果我的代码成为2050年无所不在的符号量级系统的瓶颈,那么,我敢打赌,有人可以解决这个问题并对其进行优化.

现在,第二次尝试非常接近我想要的.尽管转换int为某些输入的实现定义,但是unsigned标准保证转换为保留模UINT_MAX + 1的值.所以条件确实检查我想要什么,它将在我可能遇到的任何系统上编译成什么.

但是......我仍然在int没有首先检查它是否会调用实现定义的行为.在2050年的一些假设系统中,它可以做谁知道什么.所以我想说我想避免这种情况.

问题:我的"第三次尝试"应该是什么样的?

回顾一下,我想:

  • 从unsigned int转换为signed int
  • 保留值mod UINT_MAX + 1
  • 仅调用标准强制行为
  • 在具有优化编译器的典型二进制补码机器上编译成无操作

[更新]

让我举一个例子来说明为什么这不是一个微不足道的问题.

考虑具有以下属性的假设C++实现:

  • sizeof(int) 等于4
  • sizeof(unsigned) 等于4
  • INT_MAX 等于32767
  • INT_MIN等于-2 …

c++ integer casting integer-overflow language-lawyer

83
推荐指数
3
解决办法
4万
查看次数

纯函数:“无副作用”是否意味着“在给定相同输入的情况下始终相同的输出”?

定义函数的两个条件pure如下:

  1. 无副作用(即仅允许更改本地范围)
  2. 给定相同的输入,始终返回相同的输出

如果第一个条件始终为真,那么是否有第二次条件不为真?

即真的只有第一个条件才需要吗?

javascript functional-programming language-lawyer pure-function

83
推荐指数
4
解决办法
6507
查看次数

包含未定义行为的源代码会使编译器崩溃合法吗?

假设我去编译一些编写不佳的C ++源代码,这些源代码会调用未定义的行为,因此(正如他们所说)“任何事情都可能发生”。

从C ++语言规范在“合格”编译器中认为可接受的角度来看,这种情况下的“任何情况”是否包括编译器崩溃(或窃取我的密码,或者在编译时出现异常或错误),或者未定义行为的范围专门限于生成的可执行文件运行时会发生什么?

c++ undefined-behavior language-lawyer

83
推荐指数
2
解决办法
7746
查看次数

C++中逗号运算符的不同行为与返回?

这个(注意逗号运算符):

#include <iostream>
int main() {
    int x;
    x = 2, 3;
    std::cout << x << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出2.

但是,如果您使用return逗号运算符,则:

#include <iostream>
int f() { return 2, 3; }
int main() {
    int x;
    x = f();
    std::cout << x << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出3.

为什么逗号运算符的行为与return

c++ return operator-precedence comma-operator language-lawyer

80
推荐指数
3
解决办法
5479
查看次数

自C++ 17以来,具有正确地址和类型的指针仍然始终是有效指针吗?

(参考这个问题和答案.)

在C++ 17标准之前,[basic.compound]/3中包含以下句子:

如果类型T的对象位于地址A,则类型为cv T*的指针(其值为地址A)被称为指向该对象,而不管该值是如何获得的.

但是自从C++ 17以来,这句话已被删除.

例如,我相信这句话使这个示例代码定义,并且从C++ 17开始这是未定义的行为:

 alignas(int) unsigned char buffer[2*sizeof(int)];
 auto p1=new(buffer) int{};
 auto p2=new(p1+1) int{};
 *(p1+1)=10;
Run Code Online (Sandbox Code Playgroud)

在C++ 17之前,p1+1保持地址*p2并具有正确的类型,因此*(p1+1)是指向*p2.在C++中,17 p1+1是一个指向前端指针,所以它不是指向对象指针,我相信它不是可以解除引用的.

对标准权的这种修改的解释是否还有其他规则来补偿所引用的句子的删除?

c++ pointers language-lawyer c++14 c++17

80
推荐指数
2
解决办法
4177
查看次数

永远不会执行的代码可以调用未定义的行为吗?

调用未定义行为的代码(在此示例中,除以零)将永远不会执行,程序是否仍未定义行为?

int main(void)
{
    int i;
    if(0)
    {
        i = 1/0;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我认为它仍然是未定义的行为,但我在标准中找不到支持或否认我的任何证据.

那么,有什么想法吗?

c language-lawyer

79
推荐指数
3
解决办法
4316
查看次数

由不同编译器调用的不同强制转换操作符

考虑以下简短的C++程序:

#include <iostream>

class B {
public:
    operator bool() const {
        return false;
    }
};

class B2 : public B {
public:
    operator int() {
        return 5;
    }
};

int main() {
    B2 b;
    std::cout << std::boolalpha << (bool)b << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

如果我在不同的编译器上编译它,我会得到各种结果.使用Clang 3.4和GCC 4.4.7打印true,而Visual Studio 2013打印false,这意味着它们调用不同的强制转换操作符(bool)b.根据标准,这是正确的行为?

在我的理解operator bool()需要转变,而operator int()将需要intbool转换,所以编译器应该选择第一个.是否const做一些与该是由编译器认为更"贵"常量转换?

如果我删除了const,所有编译器同样产生false输出.另一方面,如果我将两个类组合在一起(两个运算符将在同一个类中),则所有三个编译器都将生成true输出.

c++ language-lawyer

79
推荐指数
2
解决办法
2449
查看次数

C++ - 为什么不能使用'const'限定符创建静态成员函数

今天我遇到了问题.我需要一个static会员功能,const不是必须而是更好.但是,我没有成功.任何人都可以说为什么或如何?

c++ static language-lawyer const-method

78
推荐指数
2
解决办法
4万
查看次数

为什么019不是JavaScript语法错误?或者为什么019> 020

如果我输入019 > 020JavaScript控制台(在Chrome和Firefox中测试),我会得到答案true.

这是因为020被解释为OctalIntegerLiteral(等于16),而019显然被解释为DecimalLiteral(和等于19).由于19是大于16,019 > 020true.

令我困惑的是为什么019被解释为DecimalLiteral第一名.它是哪种产品?DecimalIntegerLiteral不允许019:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt
Run Code Online (Sandbox Code Playgroud)

OctalIntegerLiteral也不允许019(因为9不是八进制数字):

OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

OctalDigit :: one of
    0 1 2 3 4 5 6 7
Run Code Online (Sandbox Code Playgroud)

因此,从我在规范中看到的,019实际应该被拒绝,我不明白为什么它被解释为十进制整数.

我想这里有一些兼容性规则,但我找不到正式的定义.可以请任何人帮我这个吗?

(为什么我需要这个:我正在使用JavaCC为Java开发一个JavaScript/ECMAScript解析器,并且必须特别注意规范 - 以及它的偏差.)

javascript grammar javacc language-lawyer ecmascript-5

78
推荐指数
1
解决办法
2544
查看次数

这个结构如何具有sizeof == 0?

有一个旧帖子要求一个sizeof可以返回的构造0.高信誉用户有一些高分答案说,按标准,没有类型或变量可以有0的大小.我同意100%.

然而,这个新的答案提出了这个解决方案:

struct ZeroMemory {
    int *a[0];
};
Run Code Online (Sandbox Code Playgroud)

我正要进行投票和评论,但是在这里度过的时间教会我检查我100%肯定的事情.所以...让我惊讶的是,gccclang显示出相同的结果:sizeof(ZeroMemory) == 0.更重要的是,变量的大小是0:

ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...
Run Code Online (Sandbox Code Playgroud)

Whaaaat ...?

Godbolt链接

这怎么可能?

c++ sizeof language-lawyer

78
推荐指数
4
解决办法
5114
查看次数