严格别名会阻止我们使用不兼容的类型访问相同的内存位置.
int* i = malloc( sizeof( int ) ) ; //assuming sizeof( int ) >= sizeof( float )
*i = 123 ;
float* f = ( float* )i ;
*f = 3.14f ;
Run Code Online (Sandbox Code Playgroud)
根据C标准,这将是非法的,因为编译器"知道" 左值int不能访问float.
如果我使用该指针指向正确的内存,如下所示:
int* i = malloc( sizeof( int ) + sizeof( float ) + MAX_PAD ) ;
*i = 456 ;
Run Code Online (Sandbox Code Playgroud)
首先,我为内存分配内存int,float最后一部分是允许float存储在对齐地址的内存.float需要在4的倍数上对齐,MAX_PAD通常是16个字节中的8个,具体取决于系统.在任何情况下,MAX_PAD足够大,所以float可以正确对齐.
然后,我写的int进入i,到目前为止,一切顺利.
float* …Run Code Online (Sandbox Code Playgroud) C11标准声明:
5.1.2.2.1程序启动
程序启动时调用的函数名为main.该实现声明此函数没有原型.它应定义为返回类型
int且没有参数:Run Code Online (Sandbox Code Playgroud)int main(void) { /* ... */ }或者有两个参数(这里称为
argc和argv,虽然可以使用任何名称,因为它们是声明它们的函数的本地名称):Run Code Online (Sandbox Code Playgroud)int main(int argc, char *argv[]) { /* ... */ }或同等学历; 10),或以某种其他实现定义的方式.
10)因此,int可以被
typedef定义为的名称替换int,或者argv可以写成类型char ** argv,等等.
我们将忽略这一部分:或者以其他一些实现定义的方式.因为我只对与上述两个例子相当的定义感兴趣.
这是否是main的有效定义,char* a[4]并且char**是等效的:
int main(int argc, char* argv[4]){/*...*/}
Run Code Online (Sandbox Code Playgroud)
我们假设一个VLA数组如何printf返回一个正的int值:
int main(int argc, char* argv[printf("Hello there!")]){/*...*/}
Run Code Online (Sandbox Code Playgroud) 以下是代码段.我想知道line no. 17在c中类型转换是否合法?
#include <stdio.h>
typedef int twoInts[2];
void print(twoInts *twoIntsPtr);
void intermediate (twoInts twoIntsAppearsByValue);
int main () {
twoInts a;
a[0] = 0;
a[1] = 1;
print(&a);
intermediate(a);
return 0;
}
void intermediate(twoInts b) {
print((int(*)[])b); // <<< line no. 17 <<<
}
void print(twoInts *c){
printf("%d\n%d\n", (*c)[0], (*c)[1]);
}
Run Code Online (Sandbox Code Playgroud)
此外,当我将定义更改intermediate为
void intermediate(twoInts b) {
print(&b);
}
Run Code Online (Sandbox Code Playgroud)
我在编译时遇到警告,而o/p不正确.
1.c:17:11: warning: passing argument 1 of print from incompatible pointer type
print(&b);
^
1.c:5:6: note: expected int …Run Code Online (Sandbox Code Playgroud) 在学习c的同时,我实现了自己的memcpy功能.我uint32_t在函数中使用了更宽的类型().(为简单起见,该函数仅限于4的倍数且数据正确对齐的类型)
void memcpy4( void* dst , void* src , int size )
{
size /= 4;
for ( int i = 0 ; i < size ; i++ )
((uint32_t*)dst)[i] = ((uint32_t*)src)[i];
}
Run Code Online (Sandbox Code Playgroud)
我做了关于类型惩罚和严格别名的阅读,我相信上面的功能打破了规则.正确的实现是这样的,因为你可以使用char:
void memcpy4( void* dst , void* src , int size )
{
for ( int i = 0 ; i < size ; i++ )
((char *)dst)[i] = ((char *)src)[i];
}
Run Code Online (Sandbox Code Playgroud)
我试图通过一个联盟进行一些投射,但事实证明这也是无效的.
如何用更广泛的类型实现这样的功能而不破坏严格的别名规则?
假设使用c11编译代码并启用严格别名.
我不是在寻找一种不同的方法,我想关注这个具体的问题,如果它有效或者为什么不能.
(如果我无意中犯了一些无关的错误,请告诉我,我会修复它)
c11标准说:
6.2.5.28所有指向结构类型的指针应具有相同的表示和对齐要求.
6.7.2.1.6结构是由一系列成员组成的类型,其存储按有序顺序分配
这意味着结构A和B中指针大小和指针对齐方式相同.
#include <stdio.h>
#include <stdlib.h>
struct S1
{
int i ;
} ;
struct S2
{
float f ;
} ;
struct A
{
struct S1* p ;
} ;
struct B
{
struct S2* p ;
} ;
int main( void )
{
Run Code Online (Sandbox Code Playgroud)
结构A和B具有指向结构S1和S2的指针,结构A和B保证具有相同的大小和对齐.
我们有一个struct B成员指针是struct S2指针,但指向一些struct S1,它使用void*cast实现.
struct S1 s1 = { 0 } ;
struct B* b = malloc( sizeof( *b ) ) ;
b->p = ( void* ) …Run Code Online (Sandbox Code Playgroud) GNU C中允许零长度数组,因此可以进行初始化
struct line {
int length;
char contents[0];
};
struct line *thisline = (struct line *)
malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
Run Code Online (Sandbox Code Playgroud)
注意:我在这里指的是这个页面:http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html (提供C中可变长度结构的基本介绍)
它继续说:"在ISO C90中,你必须给内容一个长度为1,这意味着你要浪费空间或使参数复杂化为malloc."
那是什么意思?有人可以举例说明如何在C90中初始化变长结构以帮助理解吗?
尝试使用COM和CoCreateInstance()在C中使用MinGW-w64编译示例代码失败.
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <stdlib.h>
#include <stdio.h>
extern const CLSID CLSID_MMDeviceEnumerator;
extern const IID IID_IMMDeviceEnumerator;
int main( void )
{
CoInitialize( NULL );
LPVOID device = NULL;
const HRESULT ok = CoCreateInstance( &CLSID_MMDeviceEnumerator, NULL,
CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator,
&device );
CoUninitialize();
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
编译:gcc main.c libole32.a -Wall -Wextra -oa
即使在mmdeviceapi.h中定义了CLSID_MMDeviceEnumerator,也找不到它.实际上从示例代码中删除我的extern定义给出了相同的结果,因为两个externs似乎都在mmdeviceapi.h中定义
当我使用__uuidof并使用g ++进行编译时,代码工作正常,但__uuidof的这个C"替换"却没有.
为什么没有找到COM标识符?
我的函数从对象返回一个浮点值.如果函数找不到合适的浮点值,则应返回错误,以便我可以在代码中正确处理它.
我的问题是如何返回错误.
添加额外参数并使用它来设置错误标记的选项不是首选.
我可以返回一个神奇的值,这是一个有效的选项吗?我在程序中的浮点值永远不会超过非常大的数字(从不超过10 ^ 12),因此返回FLT_MAX来检查错误可能是一个选项.
有更好的(便携式)方式吗?
出于特定原因,我想通过取消引用结构的指针来仅访问结构的第一个成员.
我想知道这是否合法,或者在某些情况下是否会导致UB; 什么是正确的解决方案,如果这个有任何问题.
谢谢.
#include <stdio.h>
#include <stdlib.h>
typedef struct test_s
{
void * data ;
struct test_s * next ;
} test_t ;
int main( void )
{
test_t * t = calloc( 1 , sizeof( test_t ) ) ;
int n = 123;
t->data = &n ; //int is used only for an address, this could be anything, an object for example
void ** v = ( void* )t ;
printf("Address of n: %p\nAddress of *t: %p\n\n" , …Run Code Online (Sandbox Code Playgroud) 我有一个结构定义,只在声明它的.c文件中可见.
struct private
{
int n ;
void* data ;
int field ;
}
Run Code Online (Sandbox Code Playgroud)
访问成员的唯一方法是在同一文件中定义并在标头中声明的函数.
我声明了一个在任何地方都可见的标题中的结构
struct public
{
int n ;
void* data ;
}
Run Code Online (Sandbox Code Playgroud)
然后我有一个函数返回实际上私有结构化的公共结构
struct public* this = GetPrivateStruct() ; //function returns pointer to struct private malloced internally, casted to public struct
this->n = 123 ;
Run Code Online (Sandbox Code Playgroud)
到目前为止,代码是正确的,没有未定义的行为.
但是,我可以使用const成员来创建公共结构吗?
struct public
{
const int n ;
const void* data ;
}
Run Code Online (Sandbox Code Playgroud)
所以只允许阅读:
void* private_struct = GetPrivateStruct() ;
struct public* this = ( struct public* )private_struct ;
this->n = …Run Code Online (Sandbox Code Playgroud) 基本上,我在C中有一个内联函数:
struct array {
unsigned long size;
void* items;
};
typedef struct array* Array;
inline Array array_create(unsigned long initsize);
inline void array_free(Array this);
Run Code Online (Sandbox Code Playgroud)
我是否可以this在这种情况下自由使用关键字,或者更好地避免它,以及为什么(不是)?
编辑:这个问题起源于我使用的代码中的一个错误,inline void array_free(Array array);它改变了结果sizeof(array);并给了我使用的想法,this而不是适应(在我看来丑陋)sizeof(struct array);.
我在C#中创建自己的DateTime类,由于某种原因我的检查不起作用.当我运行程序并输入一个日期时,它总是停止并到达"Day"方法的最后一行并说"ArgumentOutOfException.无论如何要解决这个问题并使我的检查称为"值"工作?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace date
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("\t\t\t\t\t\tNextDate Application\n\t\t\t\t\t-------------------------------------");
Console.WriteLine("please enter date as dd/MM/yyyy");
int day;
int month;
int year;
string[] read = Console.ReadLine().Split('/');
day = int.Parse(read[0]);
month = int.Parse(read[1]);
year = int.Parse(read[2]);
Date date = new Date(day, month, year);
Console.WriteLine("{0}/{1}/{2}", date.Day, date.Month, date.Year);
Console.ReadLine();
}
class Date
{
private int _month; // 1-12
private int _day; // 1-31 depending on month
private int _year; …Run Code Online (Sandbox Code Playgroud)