标签: language-lawyer

C的main()函数的有效签名是什么?

C中主要功能的有效签名究竟是什么?我知道:

int main(int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)

还有其他有效的吗?

c signature entry-point language-lawyer function-prototypes

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

std :: stoi实际上是否可以安全使用?

我与某人谈论了垮台事件std::stoi.坦率地说,它在std::strtol内部使用,如果报告错误则抛出.但是,根据他们的说法,std::strtol不应该为输入报告错误"abcxyz",导致stoi不抛出std::invalid_argument.

首先,这里有两个在GCC上测试过的关于这些案例行为的程序:
strtol
stoi

他们都表现出成功"123"和失败"abc".


我查看标准以获取更多信息:

§21.5

Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that  
no conversion could be performed. Throws out_of_range if the converted value is  
outside the range of representable values for the return type.
Run Code Online (Sandbox Code Playgroud)

总结了依赖的行为strtol.那怎么样strtol?我在C11草案中找到了这个:

§7.22.1.4

If the subject sequence is empty or does not have the expected form, no  
conversion is performed; the value …
Run Code Online (Sandbox Code Playgroud)

c++ standards language-lawyer

58
推荐指数
1
解决办法
4万
查看次数

char*和std :: uint8_t之间的reinterpret_cast* - 安全吗?

现在我们有时必须使用二进制数据.在C++中,我们使用字节序列,因为开头char是我们的构建块.定义为sizeof1,它是字节.char默认情况下,所有库I/O函数都使用.一切都很好,但总是有一点担心,有点奇怪,一些人的错误 - 一个字节中的位数是实现定义的.

所以在C99中,决定引入几个typedef让开发人员轻松表达自己的固定宽度整数类型.当然可选,因为我们从不想伤害便携性.其中uint8_t,迁移到C++ 11中std::uint8_t,固定宽度的8位无符号整数类型,对于真正想要使用8位字节的人来说是完美的选择.

因此,开发人员接受了新工具并开始构建库,这些库明确表示它们接受8位字节序列std::uint8_t*,std::vector<std::uint8_t>或者其他方式.

但是,或许经过深思熟虑,标准化委员会决定不要求实施,std::char_traits<std::uint8_t>因此禁止开发人员轻松,便携地实例化,比如说,std::basic_fstream<std::uint8_t>并轻松读取std::uint8_t二进制数据.或许,我们中的一些人不关心字节中的位数并且对它感到满意.

但遗憾的是,两个世界相互冲突,有时您必须将数据作为char*并将其传递给期望的库std::uint8_t*.但是等等,你说,是不是char变量位并std::uint8_t固定为8?它会导致数据丢失吗?

嗯,这里有一个有趣的标准.的char定义为保持正好一个字节和字节是内存的最低可寻址的块,所以用比特宽度比的较小不能有一个类型char.接下来,它被定义为能够保存UTF-8代码单元.这给了我们最小--8位.所以现在我们有一个typedef,它要求是8位宽,并且是一个至少8位宽的类型.但有其他选择吗?是的,unsigned char.请记住,签名char是实现定义的.还有其他任何一种 谢天谢地,没有.所有其他整数类型都需要超出8位的范围.

最后,std::uint8_t是可选的,这意味着如果未定义使用此类型的库将无法编译.但如果它编译呢?我可以非常自信地说,这意味着我们在8位字节的平台上CHAR_BIT == 8.

一旦我们有这方面的知识,我们已经8位字节,这std::uint8_t是实现为char或者unsigned char,我们可以假设,我们可以做reinterpret_castchar*std::uint8_t*,反之亦然?它是便携式的吗?

这是我的Standardese阅读技巧让我失望的地方.我读了关于安全派生的指针([basic.stc.dynamic.safety]),据我所知,以下内容:

std::uint8_t* buffer = /* ... */ ;
char* buffer2 …
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing language-lawyer c++11 uint8t

58
推荐指数
2
解决办法
1万
查看次数

C++ 14中引入的哪些更改可能会破坏用C++ 11编写的程序?

介绍

随着C++ 14(又名C++ 1y)标准处于接近最终的状态,程序员必须问自己有关向后兼容性以及与此相关的问题.


这个问题

该问题的答案中,指出该标准有一个附录,专门用于有关修订之间变化的信息.

如果可以解释前面提到的附录中的这些潜在问题,或许在任何与那里提到的相关的正式文件的帮助下,将会有所帮助.

  • 根据标准:C++ 14中引入的哪些更改可能会破坏用C++ 11编写的程序?

c++ language-lawyer c++11 c++14

58
推荐指数
1
解决办法
5万
查看次数

为什么不将`std :: initializer_list`定义为文字类型?

这是这个问题的后续问题:声明constexpr initializer_list对象是否合法?.

从C++ 14开始,std::initializer_list该类的所有方法都标有constexpr.能够通过执行来初始化实例似乎很自然, constexpr std::initializer_list<int> list = {1, 2, 3}; 但是Clang 3.5抱怨list没有被常量表达式初始化. 正如dyp在评论中指出的那样,任何std::initializer_list文字类型的要求似乎都从规范中消失了.

如果我们甚至不能将类完全定义为constexpr,那么有什么意义呢?这是标准中的疏忽,将来会得到修复吗?

c++ initializer-list language-lawyer constexpr c++14

58
推荐指数
1
解决办法
2635
查看次数

为什么在for循环中允许任意目标表达式?

我不小心写了这样的代码:

foo = [42]
k = {'c': 'd'}

for k['z'] in foo:  # Huh??
    print k
Run Code Online (Sandbox Code Playgroud)

但令我惊讶的是,这不是语法错误.相反,它打印{'c': 'd', 'z': 42}.

我的猜测是代码翻译成字面意思:

i = iter(foo)
while True:
    try:
        k['z'] = i.next()  # literally translated to assignment; modifies k!
        print k
    except StopIteration:
        break
Run Code Online (Sandbox Code Playgroud)

但是......为什么语言允许这样做?我希望在for-stmt的目标表达式中只允许使用单个标识符和标识符元组.是否存在实际有用的情况,而不仅仅是一个奇怪的问题?

python for-loop language-lawyer

58
推荐指数
4
解决办法
2899
查看次数

加法赋值+ =表达式中的行为

最近我遇到了这个问题:分配运营商链理解.

在回答这个问题,我开始怀疑我自己的加法赋值运算符的行为的理解+=或任何其他operator=(&=,*=,/=等).

我的问题是,a下面的表达式中的变量何时更新到位,以便在评估期间其更改的值反映在表达式的其他位置,它背后的逻辑是什么?请看下面两个表达式:

表达1

a = 1
b = (a += (a += a))
//b = 3 is the result, but if a were updated in place then it should've been 4
Run Code Online (Sandbox Code Playgroud)

表达2

a = 1
b = (a += a) + (a += a)
//b = 6 is the result, but if a is not updated in place then it should've been 4
Run Code Online (Sandbox Code Playgroud)

在第一个表达式中,当(a …

javascript java language-lawyer compound-assignment

58
推荐指数
2
解决办法
2782
查看次数

为什么析构函数需要一个未删除的对象?

struct A
{
    ~A() = delete;
};

int main()
{
    new A{};
}
Run Code Online (Sandbox Code Playgroud)

这无法编译,并显示错误消息:

错误:使用已删除的函数'A :: ~A()'new A {};

据我所知,我没有破坏对象,为什么它试图调用析构函数?

用GCC 8.1.0编译

g++ -std=c++17 -O2
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer

58
推荐指数
1
解决办法
2582
查看次数

为什么C++ 11包含一个关于比较void指针的奇怪子句?

在检查另一个问题的引用时,我注意到C++ 11中的一个奇数子句,在[expr.rel]3:

指针void(后指针转化)可以进行比较,以确定其结果如下:如果两个指针表示相同的地址或均为空指针值,其结果是true,如果操作者 <=>=false其他方式; 否则结果未指定.

这似乎意味着,一旦两个指针被投入void *,它们的排序关系就不再有保证; 例如,这个:

int foo[] = {1, 2, 3, 4, 5};
void *a = &foo[0];
void *b = &foo[1];
std::cout<<(a < b);
Run Code Online (Sandbox Code Playgroud)

似乎没有具体说明.

有趣的是,这个子句在C++ 03中不存在并且在C++ 14中消失了,所以如果我们采用上面的例子并应用C++ 14的措辞,我会说3.1

  • 如果两个指针指向同一数组的不同元素或其子对象,则指向具有较高下标的元素的指针比较大.

将应用,作为ab指向同一数组的元素,即使它们已被转换为void *.请注意,3.1的措辞在C++ 11中几乎完全相同,但似乎被该void *子句覆盖了.

我的理解是对的吗?在C++ 11中添加并立即删除的奇怪子句有什么意义?或者它可能仍然存在,但是被标准的其他部分移动/隐含?

c++ pointers comparison-operators language-lawyer c++11

58
推荐指数
1
解决办法
2978
查看次数

为什么`int;`在C中编译好,但在C++中没编译?

请考虑以下程序(请参阅此处的实时演示).

#include <stdio.h>
int main(void)
{
      int ;  // Missing variable name
      puts("Surprise");
}
Run Code Online (Sandbox Code Playgroud)

我的编译器gcc 4.8.1给出了以下警告:

[警告]空声明中无用的类型名称[默认启用]

为什么编译好?我不应该得到编译错误吗?当我将它编译为C++程序时,g ++ 4.8.1给出以下错误:

[错误]声明没有声明任何内容[-fpermissive]

c c++ gcc variable-declaration language-lawyer

57
推荐指数
3
解决办法
4532
查看次数