我上次在1997年IIRC左右专业使用C. 从那以后我使用了很多C++.现在,我发现我需要再次使用一些C.
我确信的一件事是,我不能只删除明显的C++特性(例如类)并期望一切都能正常工作.有各种不太明显的语法更改.我只是不记得它们是什么.
有没有一个很好的参考,再次进行转换,但返回到C?如果它解释了C99(以及后来的?)的变化那就更好了.
该标准指定如果新大小更大,则重新分配空间的内容是不确定的.
如果保留先前分配的空间的内容很重要,那么重新分配数据的最佳方法如下:将其复制到堆栈,从堆中释放它,在堆上分配更多空间,然后复制回堆?还有另一种安全的方法吗?
实现数据结构的最佳方法是像动态增长的数组一样只能以链表的形式增长吗?
我已经实现了一个循环缓冲区,我想要一个简洁的方法来更新缓冲区指针,同时正确处理环绕.
假设一个大小为10的数组,我的第一个响应是:
size_t ptr = 0;
// do some work...
p = ++p % 10;
Run Code Online (Sandbox Code Playgroud)
静态分析,以及gcc -Wall -Wextra,由于序列点违规而正确地拍了我的手腕以查找未指定的行为.明显的修复方法如下:
p++;
p %= 10;
Run Code Online (Sandbox Code Playgroud)
然而,我正在寻找更简洁的东西(即一个单行)来"封装"这个操作.建议?除了p ++之外; p%= 10; :-)
// File foo1.c :
#include <stdio.h> // once
void foo1(void);
void foo1(void){
puts("foo1");
}
// File foo2.c :
#include <stdio.h> // again
void foo2(void);
void foo2(void){
puts("foo2");
}
// File foomain.c :
#include <stdio.h> // yet again
void foo1(void); // again
void foo2(void); // again
int main(void){
foo1();
foo2();
puts("foomain");
return 0;
}
// create object files
gcc -fPIC foo1.c -o foo1.o // 1 stdio.h
gcc -fPIC foo2.c -o foo2.o // 1 stdio.h
// create shared library
gcc -fPIC -shared …Run Code Online (Sandbox Code Playgroud) 我正在写一个大学项目.用标准C99写.其中一个要求是缺少exit(); 功能.是否可以实现类似的功能?我试图创建一个使用减号argc调用main的函数来检测退出.这是一个愚蠢的尝试,因为第一个主要继续.
只是对项目的描述指定了exit()使用exit来减少分数.我明白它要求我通过指针运行代码并在函数的返回值中返回一个错误.我对这种做法更感兴趣.只为我自己.
在C99标准的第7.19.6.1节第8 节中:
c如果不存在l长度修饰符,则将int参数转换为aunsigned char,并写入生成的字符.
在C99标准的第7.19.6.1节第9段中:
如果任何参数不是相应转换规范的正确类型,则行为未定义.
fprintf函数是否需要int参数?例如,将unsigned int结果传递给未定义的行为:
unsigned int foo = 42;
fprintf(fp, "%c\n", foo); /* undefined behavior? */
Run Code Online (Sandbox Code Playgroud)
这让我很担心,因为实施可能被定义char为具有与unsigned char(第6.2.5段第15段)相同的行为.
对于这些情况,整数提升可能要求在某些实现中char要提升unsigned int.因此,将以下代码留给那些实现的未定义行为风险:
char bar = 'B';
fprintf(fp, "%c\n", bar); /* possible undefined behavior? */
Run Code Online (Sandbox Code Playgroud)
int变量和字面int常量的值传递给唯一安全的方法fprintf与%c符?这是用GCC(带-std = c99)和G ++(带-std = c ++ 98)编译的代码:
void fun()
{}
int main()
{
fun(1,2,3);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC成功编译了代码,但G ++提出了这个问题:
error: too many arguments to function ‘int fun()’
我完全感到困惑.
我知道C++应该与C兼容,但这个案例表明我不兼容.这种情况是通过设计发生的?
我正在尝试在Windows PowerShell中设置一个"gcc99"别名,它等于"gcc -std = C99 -pedantic -Wall".我们的想法是使用更少的击键来确保GCC以c99模式运行.(我已尽力使以下帖子中的指南适应Windows PowerShell:在GCC中设置std = c99标志)
当我在设置这样的别名(下面的图1)后尝试编译时,我收到一个错误.作为参考,如果我使用扩展命令进行编译,我不会收到此错误(参见下面的图2).作为测试,我尝试将gc99设置为"gcc"的别名(没有其他值)并且它工作正常(参见下面的3).请忽略我在代码中尚未解决的许多警告:)
有什么建议?
(我不确定为什么我的标题没有出现在下面的图片中.我正在使用自动创建的图片格式,例如,对于第一张图片:" 标题 "后面跟着" 1:链接"下一行.)



阅读完C99标准后,我找不到任何禁止定义f下面功能的部分:
struct s { double d; };
int f() {
if (0) return (struct s){.d = 3.14};
// There is intentionally no return statement of type int, which is valid
}
int main() {
f();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
特别是,应该定义该程序的行为,因为返回值是(a)从未达到过的,并且(b)从未使用过,即使它已达到.
尽管如此,我的大多数编译器(GCC,Clang和CompCert)都会阻止编译此程序,但会出错returning 'struct s' from a function with incompatible result type 'int'.我确实设法编译它tcc,但我不知道它是否主要是由于运气(即缺乏验证).
有人可以确认这个程序在语法上是否有效C99,以及它的行为是否完全明确,或者说明标准禁止它的位置?
我实际上更喜欢我的编译器拒绝它,但是例如一些宏定义可以产生类似于这个的代码,所以如果它们是有效的,接受这些程序实际上是有用的.
背景
下面是我可以找到的C99标准的可能相关的摘录,以及我为什么不应该禁止我的程序在语法上有效和语义定义良好的原因:
§6.8.6.4退货声明
§6.8.6.4.1带有表达式的return语句不应出现在返回类型为void的函数中.不带表达式的return语句只能出现在返回类型为void的函数中.
在我的代码中,我们有一个void非void返回的非函数,所以一切似乎都很好.
§6.8.6.4.3如果执行带有表达式的return语句,则表达式的值将作为函数调用表达式的值返回给调用者.如果表达式的类型与其出现的函数的返回类型不同,则通过赋值给具有函数返回类型的对象来转换该值.
因为从不执行return语句,所以不适用.
§6.9.1函数定义
§6.9.1.12如果到达了终止函数的},并且调用者使用了函数调用的值,则行为是未定义的.
调用者不使用函数调用的结果,因此应该定义行为.
对于更大任务的一部分,我被要求实现一个翻转整数中任意位的函数.问题是"整数"可以是c中的任何默认整数类型,从int8_t到uint64_t,我不知道它将是哪一个.(事实上,我的代码已经在所有这些类型上进行了测试)
这是我对这个问题的尝试:
//NOTE: g_int is the generic integer, it's typedef'd in a .h file
g_int flip_bit(g_int b, uint8_t i){
//Code that makes sure i is a valid amount to shift by, there's a macro
//that defines the upper bound of i in a .h file.
g_int flipped = b ^ (1<<i);
return flipped;
}
Run Code Online (Sandbox Code Playgroud)
此代码异或的i在第i比特b与1,而在其他位b为0.这应当翻转i个比特,同时留下其余部分保持不变.对此感到满意,我在所有这些不同的整数大小上测试了我的代码,然后将其打开.但是,我必须测试不够,因为我的代码在int64_t和uint64_t都失败了.
我对int64_t和uint64_t做了什么错误,我能做些什么来让我的方法工作而不完全改变它?