Tag: language lawyer

如何检查字符常量是否符合ASCII?

对我的这个答案的早期版本的评论提醒我,我不能假设’A’ , ‘B’ , ‘C’等具有连续的数值。 我有点假设C或C ++语言标准保证这是事实。 那么,我该如何确定连续字母字符的值本身是否连续? 或者更确切地说,我如何确定单引号中可以表达的字符常量是否具有数字值的ASCII代码? 我问的是如何在C和C ++中做到这一点。 显然C语言也可以在C ++中运行,但是如果有一个C ++ ish工具来做这个我也对它感兴趣。 另外,我问的是最新的相关标准(C11,C ++ 17)。

什么是“无效的转换规范”?

根据C11 ,章节§7.21.6.1,P9 如果转换规范无效,则行为未定义。 282)如果任何参数不是相应转换规范的正确类型,则行为未定义。 到时候,我的理解是,为 char str [] = “Sourav”; 像printf(“%S”, str);这样的语句printf(“%S”, str); 属于第一句,没有CS为%S (大写) 像printf(“%d”, str);这样的语句printf(“%d”, str); 属于第二句(CS和参数类型不匹配,但%d 不是 “无效”CS,无论如何) 直到最近的评论post通知为止 。 我的理解错了吗? 第二个语句是否也可以归类为“无效”(PS-而非“错误”)转换说明符? 更新:删除答案和评论主题, 这里是 <10K用户的快照 。

符合标准的字符串是否可以长于SIZE_MAX字符?

我没有在C11标准中找到任何声明字符串不能超过SIZE_MAX (其中SIZE_MAX表示size_t类型的最大值)字符的任何内容。 例如,如果size_max很long ,并且在我的实现中有一个long long类型,它严格地大于long ,那么我可以使用long long定义和索引这样的字符串。 但是,这意味着一些不寻常的情况:例如, strlen可能无法返回字符串的实际大小,因为结果将在结尾处转换为size_t ,因此将报告长度为SIZE_MAX+1的字符串为例如,大小为0。 例如,这会违反标准,从而防止这些字符串存在吗? 作为参考,7.24.6.3仅表示: 7.24.6.3 strlen函数 概要 #include size_t strlen(const char *s); 描述 strlen函数计算s指向的字符串的长度。 返回 strlen函数返回终止空字符前面的字符数。 我是否遗漏了某些东西,或者这对C11(符合标准的实施)是否完全有效?

如何在结构中引用未定义的类型是合法的?

作为回答另一个问题的一部分,我遇到了一段像这样的代码,gcc编译时没有抱怨。 typedef struct { struct xyz *z; } xyz; int main (void) { return 0; } 这是我一直用来构造指向自己的类型的方法(例如,链接列表),但我一直认为你必须命名结构,以便你可以使用自引用。 换句话说,您无法在结构中使用xyz *z ,因为此时typedef尚未完成。 但是这个特定的样本没有命名结构,它仍然编译。 我原本认为编译器中有一些黑魔法会自动翻译上面的代码,因为结构和typedef名称是相同的。 但是这个小小的美也可以: typedef struct { struct NOTHING_LIKE_xyz *z; } xyz; 我在这里想念的是什么? 这似乎是一个明显的违规,因为在任何地方都没有定义任何struct NOTHING_LIKE_xyz类型。 当我从指针更改为实际类型时,我得到预期的错误: typedef struct { struct NOTHING_LIKE_xyz z; } xyz; qqq.c:2: error: field `z’ has incomplete type 此外,当我删除struct ,我得到一个错误(解决parse error before “NOTHING […]

`typedef struct foo {int bar};`的合法性

这个问题来自问题是结构{…}; 一个类型或一个未命名的变量? 在那个问题上,OP问了一下 typedef struct student_s { char* name; int age; double height; struct student_s* next; }; 我问的是上述的合法性。 当编译包含上述代码的代码时,是否需要诊断(或使其更简单, typedef struct foo {int bar;}; )? 我的看法是合法的,从语言律师的角度来看,不需要诊断。 (旁白:我不主张使用它。它非常值得诊断。如果我错误地编写了如上所述的代码,我非常希望编译器警告我。) C11标准的第6.7节规定了声明的语法: declaration-specifiers init-declarator-list opt ; 请注意, init-declarator-list是可选的。 这可能导致人们认为typedef int; 已validation。 这不是因为标准也说明了这一点 除static_assert声明之外的声明应至少声明一个声明符(除函数的参数或结构或联合的成员之外),标记或枚举的成员。 因此typedef int; 和typedef struct {int bar}; 是非法的,因为他们没有声明声明者,标签或枚举成员。 另一方面,在我看来, typedef struct foo {int bar;}; 是合法的,因为它确实声明了一些东西。 特别是,它声明并定义了struct标签foo 。 […]

别名结构和数组符合方式

在ISO C之前的日子里,下面的代码会让人惊讶: struct Point { double x; double y; double z; }; double dist(struct Point *p1, struct Point *p2) { double d2 = 0; double *coord1 = &p1.x; double *coord2 = &p2.x; int i; for (i=0; i<3; i++) { double d = coord2[i] – coord1[i]; // THE problem d2 += d * d; return sqrt(d2); […]

没有正确的原型调用printf会调用未定义的行为吗?

这个无辜的程序是否会调用未定义的行为: int main(void) { printf(“%d\n”, 1); return 0; }

是否为明确定义的相同文件描述符创建了两个FILE?

POSIX指定了一个fdopen函数,它为文件描述符创建一个FILE 。 POSIX还指定了一个fileno函数,该函数返回FILE文件描述符。 这两个可以一起用于创建第二个FILE访问与现有文件相同的底层文件描述符: FILE *secondfile(FILE *f, const char *mode) { int fd = fileno(f); return fd >= 0 ? fdopen(fd, mode) : NULL; } 这是POSIX下定义明确的操作吗? 当我访问原始FILE和我为同一文件描述符创建的第二个FILE时会发生什么? 是否指定了交互? 如果有,怎么样? 从历史上看,Unices为您打开的20个文件使用了固定的FILE结构表。 fdopen() ,在已经与FILE关联的文件描述符上调用fdopen()会破坏现有文件并产生未定义的行为。 我不确定POSIX是否仍允许这样的stdio实现,这就是我提出这个问题的原因。

对于以前广泛支持的行为,有哪些替代品可用于C标准未定义的行为

在标准化之前的C早期,实现有各种方法来处理各种操作的exception和半exception情况。 如果没有先配置,其中一些会触发可能导致随机代码执行的陷阱。 因为此类陷阱的行为超出了C标准的范围(并且在某些情况下可能由运行程序控制之外的操作系统控制),并且避免要求编译器不允许依赖此类陷阱的代码陷阱继续这样做,可能导致此类陷阱的操作行为完全取决于编译器/平台的判断。 到20世纪90年代末,虽然C标准没有要求这样做,但每个主流编译器都采用了许多这种情况的共同行为; 使用这样的行为将允许在代码速度,大小和可读性方面进行改进。 由于不再支持请求以下操作的“明显”方式,因此在使用较旧的编译器时,应如何以不妨碍可读性的方式替换它们,也不会对代码生成产生负面影响? 出于描述的目的,假设int是32位, ui是unsigned int, si是signed int, b是unsigned char。 给定ui和b ,计算ui << b表示b == 0..31,或者可以任意表现为ui << (b & 31)的值或对于值32..255为零。 请注意,如果右侧操作数超过31时左侧操作数为零,则两种行为都是相同的。 对于仅需要在右移或左移32到255时产生零的处理器上运行的代码,计算ui << b表示b == 0..31,0表示b == 32。 .255。 虽然编译器可能能够优化条件逻辑,旨在跳过值32..255的转换(因此代码只会执行将产生正确行为的转换),我不知道如何制定这样的条件逻辑这将保证编译器不会为它生成不必要的代码。 与1和2一样,但是对于右移。 给定si和b使得b0..30和si*(1<<b)不会溢出,计算si*(1<<b) 。 请注意,使用乘法运算符会严重影响许多较旧编译器的性能,但如果移位的目的是缩放有符号值,则在操作数在整个移位期间保持负值的情况下转换为无符号会感觉错误。 给定各种整数值,执行加法,减法,乘法和移位,这样的方式是,如果没有溢出,结果将是正确的,并且如果存在溢出,则代码将产生其高位表现为非陷阱和非陷阱的值。 -UB但是以其他方式不确定时尚或将陷入可识别的平台定义的方式(并且在不支持陷阱的平台上,将简单地产生不确定的价值)。 给定指向已分配区域的指针以及指向其中内容的指针,使用realloc更改分配大小并调整上述指针以匹配,同时避免在realloc返回原始块的情况下的额外工作。 不一定可能在所有平台上,但是90年代主流平台都会允许代码确定realloc导致事物移动,并通过减去该对象的前一个基地址来确定指针到死对象的偏移量(请注意,调整需要通过计算与每个死指针相关联的偏移量,然后将其添加到新指针,而不是通过尝试计算旧指针和新指针之间的“差异” – 这将合法地失败许多分段架构)。 “超现代”编译器是否为上述提供了任何良好的替代品,这些替代品不会降低代码大小,速度或可读性中的至少一个,同时不提供其他任何改进? 据我所知,不仅99%的编译器在整个20世纪90年代都可以完成上述所有工作,但是对于每个例子,人们都可以在几乎所有这些编码器上以相同的方式编写代码。 一些编译器可能试图用无人看守的跳转表来优化左移和右移,但这是我能想到的唯一一种情况,即20世纪90年代20世纪90年代平台的编译器对“明显”的编码方式有任何问题以上任何一种。 如果那些超现代的编译器已不再支持经典forms,那么它们作为替代品提供了什么?

如果strcat函数中的目标字符串不是以null结尾,那么它是否是未定义的行为?

以下程序 // Code has taken from http://ideone.com/AXClWb #include #include #define SIZE1 5 #define SIZE2 10 #define SIZE3 15 int main(void){ char a[SIZE1] = “Hello”; char b[SIZE2] = ” World”; char res[SIZE3] = {0}; for (int i=0 ; i<SIZE1 ; i++){ res[i] = a[i]; } strcat(res, b); printf("The new string is: %s\n",res); return 0; } 有明确的行为。 […]