小编Ste*_*mit的帖子

在内存中我的变量存储在C中?

通过考虑将内存分为四个部分:数据,堆,堆栈和代码,全局变量,静态变量,常量数据类型,局部变量(在函数中定义和声明),变量(在main函数中),指针,并动态分配空间(使用malloc和calloc)存储在内存中?

我认为他们将分配如下:

  • 全局变量------->数据
  • 静态变量------->数据
  • 常量数据类型----->代码
  • 局部变量(在函数中声明和定义)--------> stack
  • 在main函数-----> heap中声明和定义的变量
  • 指针(例如char *arr,int *arr)------->堆
  • 动态分配空间(使用malloc和calloc)-------->堆栈

我只是从C的角度来指这些变量.

如果我错了,请纠正我,因为我是C的新手.

c memory types memory-management

134
推荐指数
5
解决办法
20万
查看次数

什么是"数组/指针等价"的现代术语?

几乎每个读这篇文章的人都熟悉这三个关于C的关键事实:

  1. 当您在表达式中提及数组的名称时,它会(大部分时间)计算指向数组第一个元素的指针.
  2. "数组下标"运算符[]与指针一样适用于指针.
  3. 似乎是数组的函数参数实际上声明了一个指针.

这三个事实绝对是C中数组和指针处理的核心.它们甚至不是三个独立的事实; 它们是一个中心概念的相互关联的方面.如果没有对这个概念的正确理解,就不可能正确地进行相当基本的C编程.

我今天的问题很简单,这个概念的名称什么?

我以为我是老式的,但我总是把它称为"C中数组和指针之间的等价",或简称为"数组/指针等价".但我知道你几乎不能在SO上说出这些话; 他们几乎是禁忌.

这可能看起来像一个抽象或哲学问题,所以更具体地构建它,我正在寻找的是一个简单的名词或名词短语我可以在句子中使用"是的,由于_____,数组下标可以被认为是作为指针算术的语法糖",回答,比方说,这个问题.

(但是请注意,我不是在寻找这个问题的答案,也不是为了回答"'等价'这个词有什么问题?".是的,我知道,它会误导学习者想象数组和指针是某种方式同样.当我写这个FAQ列表条目时,我确实有这种困惑.)

c arrays pointers terminology

39
推荐指数
5
解决办法
3961
查看次数

能否在序列点之间多次读取易失性变量?

我正在制作自己的 C 编译器,以尝试尽可能多地了解有关 C 的详细信息。我现在正在尝试准确地了解volatile对象是如何工作的。

令人困惑的是,代码中的每个读访问都必须严格执行(C11,6.7.3p7):

具有 volatile 限定类型的对象可能会以实现未知的方式进行修改,或者产生其他未知的副作用。因此,引用此类对象的任何表达式都应严格根据抽象机的规则进行评估,如 5.1.2.3 中所述。此外,在每个序列点,最后存储在对象中的值应与抽象机规定的值一致,除非受到前面提到的未知因素的修改。134)构成对具有易失性限定类型的对象的访问的是实现-定义。

示例:在 中a = volatile_var - volatile_var;,必须读取 volatile 变量两次,因此编译器无法优化a = 0;

同时,序列点之间的评估顺序未确定(C11,6.5p3):

运算符和操作数的分组由语法指示。除非稍后指定,否则子表达式的副作用和值计算是无序的。

示例:b = (c + d) - (e + f)未指定计算添加的顺序,因为它们是无序的。

但是,对未排序对象的评估会产生副作用(例如volatile),行为未定义(C11,6.5p2):

如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值的值计算是无序的,则行为是未定义的。如果表达式的子表达式有多个允许的排序,并且在任何排序中出现此类未排序的副作用,则行为未定义。

x = volatile_var - (volatile_var + volatile_var)这是否意味着像未定义这样的表达式?如果发生这种情况,我的编译器应该发出警告吗?

我尝试看看 CLANG 和 GCC 做了什么。既不抛出错误也不发出警告。输出的 asm 显示变量不是按执行顺序读取的,而是从左到右读取的,如下面的 asm risc-v asm 所示:

const int volatile thingy = 0;
int main()
{
    int new_thing = thingy - (thingy + thingy);
    return …
Run Code Online (Sandbox Code Playgroud)

c volatile language-lawyer c11

39
推荐指数
4
解决办法
2578
查看次数

为什么我不能返回 std::getline 的 as-if-boolean 结果?

一个标准的习语是

while(std::getline(ifstream, str))
    ...
Run Code Online (Sandbox Code Playgroud)

所以如果这有效的话,我为什么不能说

bool getval(std::string &val)
{
    ...

    std::ifstream infile(filename);

    ...

    return std::getline(infile, val);
}
Run Code Online (Sandbox Code Playgroud)

g++ 说“ cannot convert 'std::basic_istream<char>' to 'bool' in return”。

值函数return中语句的布尔bool上下文是否与 的布尔上下文有所不同while(),以至于在一个上下文中执行的魔术转换std::basic_istream在另一个上下文中不起作用?


附录:这里显然有一些版本,也许还有语言标准依赖性。我在 g++ 8.3.0 中遇到了上述错误。但我在 gcc 4.6.3 或 LLVM (clang) 9.0.0 中没有得到它。

c++ boolean ifstream

33
推荐指数
1
解决办法
2183
查看次数

什么时候 memset 为 0 不可移植?

来自GCC bug #53119 中的评论

在 C 中,{0}通用零初始值设定项与 C++ 的通用零初始值设定项等效{}(后者在 C 中无效)。每当您想要一个完整但概念上不透明或实现定义类型的零初始化对象时,就有必要使用它。C 标准库中的经典示例是mbstate_t

mbstate_t state = { 0 }; /* correctly zero-initialized */
Run Code Online (Sandbox Code Playgroud)

与常见但不可移植的相比:

mbstate_t state;
memset(&state, 0, sizeof state);
Run Code Online (Sandbox Code Playgroud)

让我感到奇怪的是,后一个版本可能是不可移植的(即使对于实现定义的类型,编译器也必须知道大小)。这里的问题是什么?什么时候是memset(x, 0, sizeof x)不可移植的?

c portability memset

26
推荐指数
2
解决办法
1406
查看次数

重载虚函数集的部分继承

我以为我理解了继承,虚函数和函数重载,但我有一个案例,其中有关于这些特性之间的相互作用的事情让我望而却步.

假设我有一个包含重载虚函数的简单基类,以及从中派生的第二个类:

class b {
 public:
    virtual int f() { return 1; }
    virtual int f(int) { return 2; }
};


class d : public b {
 public:
    virtual int f(int) { return 3; }
};
Run Code Online (Sandbox Code Playgroud)

请注意,派生类d仅覆盖其中一个重载的虚函数.

我可以实例化一个类的对象df(int)在其上调用,没问题:

d x;
std::cout << x.f(0) << std::endl;
Run Code Online (Sandbox Code Playgroud)

但是当我尝试调用0参数函数时:

std::cout << x.f() << std::endl;
Run Code Online (Sandbox Code Playgroud)

它失败!gcc说"没有匹配函数来调用'd :: f()';候选者是:virtual int d :: f(int)".clang说"函数调用的参数太少,预期为1,有0;你的意思是'b :: f'吗?" 即使d派生出来的b是0-argument f()方法,编译器也会忽略它,并试图调用d1-argument方法.

我可以通过重复派生类中的0参数函数的定义来解决这个问题:

class d : public …
Run Code Online (Sandbox Code Playgroud)

c++ inheritance virtual-functions overloading

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

大小为 0 的 qsort 未定义?

我有一份未经我证实但来自可靠来源的报告,该代码

qsort(a, n, sizeof *a, cmpfunc);
Run Code Online (Sandbox Code Playgroud)

由现代版本的 gcc 编译,就好像它已被编写一样

if(n == 0)
    __builtin_trap();
qsort(a, n, sizeof *a, cmpfunc);
Run Code Online (Sandbox Code Playgroud)

qsort显然,调用with被认为n == 0是未定义的行为。

[编辑:这里的整个前提被发现是错误的;请参阅下面的“更新 2”。]

有人指出,Posix 明确支持这种n == 0情况,但显然现有的 C 标准版本不支持这种情况

所以显而易见的问题是:

  1. C 中的调用实际上是未定义的行为qsort吗?n = 0
  2. 每个qsort任意调用的程序n是否真的有义务检查n == 0而不是qsort在这种情况下调用?
  3. 为什么 gcc 会执行这种“优化”?即使您认为调用qsortwithn == 0是未定义的,这似乎也会稍微减慢每个未定义程序的速度。

快速排序的教科书实现(我知道,这qsort不是必需的)几乎无法n = 0正确处理。我想知道 gcc 在这里的行为是否试图防止一种实现,该实现以某种方式做比if 初始调用qsort更糟糕的事情? …

c qsort undefined-behavior language-lawyer

7
推荐指数
2
解决办法
361
查看次数

标准C是否接受`{0}`作为任何结构的初始化器?

这通常被建议,作为将结构体初始化为零值的方法:

struct foo f = {0};
Run Code Online (Sandbox Code Playgroud)

还提到{}可以在gcc下使用,但这不是标准的C99.

我想知道这是否适用于一个结构,其布局可能会超出我的控制范围.我很担心,因为0它不是数组或结构的有效初始值设定项.然而,gcc --std=c99(gcc-8.1.1-1.fc28.x86_64)似乎也接受{0}了这种情况.

问题 C99是否接受{0}任何结构的初始化程序?

(或者是后来的C标准?还是相反的,是否有任何理由不依赖于此?是否存在{0}可能导致错误或警告会阻止其使用的编译器?)

我试过了什么

gcc警告(启用-Wall)表明这是标准中的某种形式的边缘情况,其中gcc被强制接受0作为任何类型的struct字段的初始化器,但它会警告它,除非你使用常见的{0}习惯用法.

struct a { int i; };
struct b { struct a a; struct a a2; };
struct c { int i[1]; int j[1]; };

struct a a = {0}; /* no error */
struct b b = {0}; /* no error */
struct c c = {0}; /* …
Run Code Online (Sandbox Code Playgroud)

c struct initialization language-lawyer

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

ntp 问题:回转与跳跃时间

ntp 不想跳过你的时钟,因为不连续的时间跳跃是不好的。它想逐渐调整你的时钟——非常缓慢。这是非常保守的:默认情况下,它不会使您的时钟偏移超过百万分之 xx (ppm)。

但是由于 ntp 非常保守,如果它发现您的时钟太远,以至于逐渐调整它会花费很长时间,它无论如何都会回退并跳过您的时钟(即使那很糟糕)。默认情况下,如果逐渐调整时钟所需的时间超过 yy 小时,则会执行此操作。

如果您愿意,您可以告诉 ntp 更快地调整您的时钟(即逐渐减少),最高可达 zz ppm。

我的问题是,xx、yy 和 zz 是什么?我知道这些阈值存在,我很确定它们已记录在案,我很确定它们是可配置的,但我永远记不起这些值,也找不到它们。

如果您知道它们是什么,理想情况下我想知道 (a) 默认值是什么和 (b) 它们的文档位置和 (c) 如何配置它们以及 (d) 实际代码在哪里做出回转或跳跃的决定。谢谢。

ntp

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

是否可以使用 fgets 或 gets_s 正确读取空字符?

假设我想从 读取stdin,并让用户输入包含空字符的字符串。fgets这可以通过or等​​字符串输入函数实现吗gets_s?或者我必须使用例如fgetcfread

这里有人想这样做。

c input null-character

5
推荐指数
2
解决办法
3968
查看次数