小编Lov*_*ure的帖子

每个空指针常量都是空指针吗?

来自 C17 草案 (6.3.2.3 \xc2\xb63):

\n
\n

值为 0 的整型常量表达式,或此类转换为类型的表达式void *,称为空指针常量67)如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与任何对象或函数的指针比较不相等。

\n

67)该宏NULL在(和其他标头)中定义<stddef.h>为空指针常量 [...]。

\n
\n

由此可见,以下是空指针常量0, 0UL, (void *)0, (void *)0UL, NULL

\n

进一步得出以下是空指针(int *)0, (int *)0UL, (int *)(void *)0, (int *)(void *)0UL, (int *)NULL。有趣的是,这些都不是“空指针常量”;看这里

\n

以下空指针常量空指针(因为void *是指针类型,并且00UL是空指针常量):(void *)0 …

c void-pointers null-pointer language-lawyer

18
推荐指数
4
解决办法
5037
查看次数

什么时候有必要或有意义为函数 f 编写 &amp;f 或为函数指针 fp 编写 *fp (除了:sizeof &amp;f)?

来自 C17 标准草案(6.3.2.1 \xc2\xb64;脚注已删除):

\n
\n

函数指示符是具有函数类型的表达式。除非它是运算sizeof符或一元&运算符的操作数,否则类型为“函数返回类型”的函数指示符将转换为类型为“指向函数返回类型的指针”的表达式。

\n
\n
    \n
  • 根据我从上面引用中省略的脚注,sizeof f(对于函数指示符f)是不符合标准的。
  • \n
  • 请注意,C11 标准还提到了_Alignof运算符。
  • \n
  • 请注意,C2x 草案还提到了typeof操作员。
  • \n
\n

结果(这里:f是函数指示符;fp是函数指针):

\n
    \n
  1. 可以将函数地址指示为&f(显式)或f(短)。
  2. \n
  3. 可以将函数调用如下:\n
      \n
    • (&f)(args)或者f(args)
    • \n
    • fp(args)或者(*fp)(args)
    • \n
    \n
  4. \n
\n

这里,

\n
    \n
  • 左手(&f)(args)/fp(args)与技术上操作函数指针的函数调用一致,并且
  • \n
  • 右边的f(args)/(*fp)(args)与函数调用对函数(而不是指向函数的指针)进行操作的天真的假设是一致的。
  • \n
\n …

c function-pointers language-lawyer

9
推荐指数
1
解决办法
200
查看次数

strncmp(s1, s2, 0) 返回的是未定义的行为(即最后一个参数为零)吗?

从标准中尚不清楚strncmp(来自string.h

int strncmp(const char *s1, const char *s2, size_t n);
Run Code Online (Sandbox Code Playgroud)

n如果其第三个参数是则应返回0

根据C17标准草案,7.24.4.4:

strncmp函数比较不超过n字符(不比较空字符后面的字符)[...]。

strncmp函数返回一个大于、等于或小于零的整数,相应地,因为 指向的 [...] 数组s1大于、等于或小于 指向的 [...] 数组s2

应该strncmp(s1, s2, 0)返回什么?或者标准对strncmp最后一个论点的情况保持沉默0

我的直觉告诉我,0作为返回值最有意义:

  • 0是最“对称”的答案(负或正返回值意味着不对称并且与未进行比较不一致)。
  • 0与假设的模型一致0,直到发现差异、n进行比较或到达字符串末尾。

但上述推理是哲学性的。

似乎该标准在技术上并未声明有关此情况的任何内容。我认为如果这样会更好

  • 显式定义结果(例如0
  • 宣布其为非法。

对于它的价值,glibc给我0(没有警告或错误)一堆简单的测试用例,例如strncmp("abc", "def", 0)使用以下编译器标志:

-Wall -Wextra -std=c90 -pedantic
-Wall -Wextra -std=c17 …
Run Code Online (Sandbox Code Playgroud)

c c-strings language-lawyer strncmp

7
推荐指数
1
解决办法
191
查看次数

说明 C 预处理器中 # 和 ## 的未指定相对计算顺序的示例

关于已接受答案的一些评论位于本问题帖子的底部。

\n
\n

问题陈述

\n

根据C标准(C17草案,6.10.3.2\xc2\xb62):

\n
\n

#[the]和运算符的求值顺序##未指定。

\n
\n

我正在寻找一个示例,其中此评估顺序很重要,并且没有其他未定义行为的实例并且没有错误。

\n

在花了一些时间处理这个问题之后,我怀疑以下方法可能有效:

\n
#define PRECEDENCETEST(a, b, c)  # a ## b\n\nPRECEDENCETEST(c, , d)\n
Run Code Online (Sandbox Code Playgroud)\n

(请注意,预处理器可以按如下方式运行:cppgcc -E(GCC),cl /E (MSVC);请参阅下面的可编译虚拟示例。另请注意,空宏参数仅自 C99 起才合法。)

\n

我的问题:根据 C 标准,这实际上可以作为一个相对评估顺序#和产生合法输出的示例吗?##正如我在本文底部所解释的那样,如果我理解正确的话,答案可能取决于标准是否允许在之后使用令牌#与最初指定的令牌不同。

\n

如果答案是“是(因为......)”,那么我们就找到了一个例子!如果答案是“不,你的例子不起作用(因为......)”,那么我稍后会想办法征求更好的例子。

\n

(请注意,该标准不要求编译器对#和具有绝对相对评估顺序##运算符具有绝对相对的求值顺序。顺序可以是:从左到右、从右到左、遵循某些其他逻辑或完全随机。)

\n

文档

\n

较旧的 GCC 文档(似乎最高版本为 6.5)指出

\n
\n

##该标准没有指定 \xe2\x80\x98 \xe2\x80\x99 运算符链的计算顺序,也没有#指定 \xe2\x80\x98 \xe2\x80\x99 …

c operator-precedence language-lawyer c-preprocessor token-pasting-operator

6
推荐指数
1
解决办法
215
查看次数

多字变量中的字顺序(以及一般标识符)

这是一个关于变量命名(或一般标识符的命名)的问题。

\n

中心语(右分支)语言往往有后名词修饰语,而中心语(左分支)语言往往有前名词修饰语。修饰语包括形容词、副词、所有格代词和指示词。这是一个例子(英文翻译:“大声的音乐”):

\n
    \n
  • 韩语(左分支): \xec\x8b\x9c\xeb\x81\x84\xeb\x9f\xac\xec\x9a\xb4 \xec\x9d\x8c\xec\x95\x85
  • \n
  • 法语(右分支):musique forte
  • \n
\n

一旦我们把例子拉长,我们就会发现,实际上,语言在这方面是非常不一致的,英语就是一个很好的例子。另外,根据我个人的经验,单词越短,它出现在左侧的可能性就越大(出于心理语言学解析的原因:您可以通过这种方式更早地辨别树结构)。但是,在命名由许多单词组成的长变量时,在这方面保持一致不是有好处吗?

\n

这里有些例子:

\n
    \n
  • redblackTree_leftSubtree_color(混合;自然英语)vs treeRedblack_subtreeLeft_color(一致右分支)\xe2\x80\x93 注意我如何没有将“subtree”更改为“treesub”(将其视为不可更改的词汇化块)
  • \n
  • old_bTree_order(混合;自然英语)与bTree_old_order(一致右分支)\xe2\x80\x93 在这种情况下,我没有将“bTree”更改为“treeB”
  • \n
  • myStrings_set_size(混合;自然英语)与stringsMy_set_size(一致右分支)
  • \n
  • len_median_sortedListCopy(混合;自然英语)与listSortedCopy_median_length(一致右分支)
  • \n
  • arrayIndexOutofboundsException[ ArrayIndexOutOfBoundsExceptionJava 中](混合;自然英语)vs exceptionArrayIndexOutofbounds(一致右分支)
  • \n
\n

我个人非常喜欢非常严格的右分支命名。这样,我们总是从高级/抽象/一般概念到低级/具体/专业概念,即从大整体到小组成部分。不用说,这违背了英语中的自然语言用法。

\n

顺便请注意,严格左分支命名的情况是,通常可以从最具体的元素猜测类型。例如,order_old_bTree几乎可以肯定是一个整数。此外,最左边的元素与当前的缩进级别很好地对齐。

\n

关于由许多组件组成的变量/标识符的分支顺序是否有任何最佳实践或指南?

\n

我浏览了非英语国家的人用英语编码的 108 个答案吗?,但我找不到任何一个解决这个方面的问题。

\n

我在相应的维基百科文章中可以找到的唯一相关内容是OF 语言的 PRIME-MODIFIER-CLASS 单词方案(除了维基百科所说的之外,我对此一无所知)。

\n

此站点上至少存在 2 个相关但编程语言\xe2\x80\x93 特定的问题:

\n

language-agnostic naming-conventions

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

为什么正则表达式量词 {n,} 比 + (在 Python 中)更贪婪?

我尝试使用正则表达式来查找由重复的双字母形成的最大长度序列,例如AABBstring 中的xAAABBBBy

正如官方文档中所述:

'*''+''?'量词都是贪婪的;它们匹配尽可能多的文本。

当我使用量词时{n,},我得到一个完整的子字符串,但+仅返回部分:

import re

print(re.findall("((AA|BB){3,})", "xAAABBBBy"))
# [('AABBBB', 'BB')]
print(re.findall("((AA|BB)+)", "xAAABBBBy"))
# [('AA', 'AA'), ('BBBB', 'BB')]
Run Code Online (Sandbox Code Playgroud)

为什么{n,}比 更贪婪+

python regex regex-greedy

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

为什么变量需要 extern 而函数不需要 extern?

在 C 中,默认情况下,变量和函数都在文件范围内具有外部链接。为什么extern仅变量需要关键字,而其他地方定义的函数不需要关键字?请注意,这个问题有两个方面。鉴于文件范围内的声明默认为外部链接:

  • 为什么历史上函数没有声明有extern或没有的区别?或者说,为什么客观上不需要这样的区分?
  • 为什么历史上变量的声明有或没有有区别extern?或者说,客观上为什么需要这样的区分?

作为一个最小的示例,让我们使用以下两个源文件(tu代表“翻译单元”)。

tu1.c

extern int i = 123;
Run Code Online (Sandbox Code Playgroud)

tu2.c

#include <stdio.h>

extern int i;

int main(void) {
  //extern int i;
  ++i;
  printf("%d\n", i);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们可以用 GCC 编译它们,如下所示:

gcc -c tu1.c
gcc -c tu2.c
gcc -o myprogram tu1.o tu2.o
Run Code Online (Sandbox Code Playgroud)

'i' initialized and declared 'extern'(GCC对第一个命令发出警告,因为它错误地认为extern“应该保留用于非定义声明”。我们可以安全地忽略它。)

让我们比较一下编译器对于略有不同的源代码版本的行为:

  • extern int i;在文件范围内tu2.c(对上述代码没有更改):is
    的输出,如预期的那样。myprogram124
  • extern int i;in main …

c language-design extern

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

为什么 scanf 解析“2E”而不解析“.” (使用GCC)作为浮点数的“匹配输入序列的前缀”?

注意:我的问题的原始版本与编译器无关,并假设 GCC(我用来进行实验)的行为完全正确,并且匹配输入序列的非空前缀不会导致匹配失败输入失败。事实证明(参见:C17 草案,7.21.6.2 \xc2\xb610),答案更有可能在编译器/库错误中找到,而不是在匹配的前缀的定义和正确处理的复杂性中找到。然而,为了保留问题的原始精神,我只是保守地对其进行了编辑(因此,最初的假设仍然在这篇文章的后半部分中体现出来)。

\n

考虑到这一点,这篇文章所涉及的问题的一个方面仍然没有解决,即:%4c示例(底部)中是否适合CD写入q[].

\n
\n

根据标准(C17 草案,6.4.4.2 \xc2\xb61),2E0(2.0) 和.5(0.5) 是有效的浮动常量,而2E.不是。

\n

然而,对于 GCC,scanf解析2E为 2.0,但它不会解析.为任何内容

\n
#include <stdio.h>\n\nint main(void) {\n    float fl;\n    char c;\n\n    printf("Please enter a floating-point number: ");\n    if (scanf("%f", &fl) == 1)\n        printf("<%.2f>\\n", fl);\n    if (scanf("%c", &c) == 1)\n        printf("[%c]\\n", c);\n\n …
Run Code Online (Sandbox Code Playgroud)

c floating-point scanf language-lawyer compiler-bug

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

为什么不允许 a++=b,而允许 c[i++]=d?

为什么按照标准不允许a++ = b;,而c[i++] = d;允许呢?

(显然,a++ = b;这是一种不好的风格,但这是一个关于仔细阅读 C 语言标准的问题。)

这是强制性的最小示例:

#include <stdio.h>

int main(void)
{
        int a = 10;
        int b = 20;
        int i = 1;
        int c[] = {30, 40};
        int d = 50;

        a++ = b; // error
        c[i++] = d;

        printf("%d\n", a); // [21]
        printf("%d\n", b); // 20
        printf("%d\n", i); // 2
        printf("%d\n", c[0]); // 30
        printf("%d\n", c[1]); // 50
        printf("%d\n", d); // 50

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

-std=c90当使用或进行编译时,GCC …

c lvalue language-lawyer pre-increment post-increment

0
推荐指数
2
解决办法
329
查看次数