I'm fairly new to C so be gentle.
I want to use the library interception method for Linux to replace calls to the OpenCL library with my own library. I understand that this can be done using LD_PRELOAD. So I can just re-implement the OpenCL functions as defined in the OpenCL header file within my own library which can then be linked against.
The problem is that this OpenCL header also contains some extern struct definitions, e.g.
typedef struct _cl_mem * cl_mem;
which are not defined within the OpenCL header. Is it possible these structs are defined within the OpenCL shared lib? If not, where might they be defined?
Cheers
Chris
That typedef declares a type pointing to a struct, the contents of which are undeclared. This means code using it can't do things like checking its size, copying the struct, or inspecting its contents - it simply has no idea what size it is.
This is a traditional technique in C to create an opaque, or private, type. You can declare the struct inside your OpenCL library, and the official header puts no restrictions on what that struct contains. It could even be empty, if all you need is an ID you can store in the pointer itself, though this is rarely done.
An example of the same technique used in the standard C library is the FILE type. It might be as simple as an integer file descriptor, or as complex as a struct containing the entire filesystem state; standard C code won't know. The particulars are known to the library only.
In short, you can declare that struct however you like - as long as you implement every function that handles that struct. The program that links to your library never handles the struct, only pointers to it.
Related
I have huge (65 mln. lines of C code) legacy codebase.
Need to track usage of single cpp numeric const (#define MAX_NUM 32) which is used to define a number of structs (struct a { ... int a[MAX_NUM]; ... };), which in turn used to define fields in other structs, which in turn... at least 4 levels of usage of this kind.
Structs in turn are used to define other consts (like #define SIZE_A sizeof(struct a))
Structs are also used to define function params.
Obviously functions use these structs to access their fields in function implementations.
And functions are called with params of these structs types.
And so on...
Could I track all this forest of chained usages with Frama-C?
Tried to track these usage chains manually - oh my, 65 mln lines of code...
Tried to understand Frame-C usage for static usage analysis - too many docs to understand at a single glance...
Frama-C does not have its own C preprocessor, it uses the system's preprocessor.
This means that the Cil (normalized) code seen by Frama-C is the version after preprocessing. Thus #define macros are not directly seen by Frama-C; the MAX_NUM constant in your example does not exist in Frama-C's AST. If it were an enum, then it would be present.
Concerning the type definitions, however, they are present in Frama-C's AST, and the graphical interface's Information panel does display type information, e.g. if you select an expression the AST, it will show its type, with clickable links to further expand type definitions, recursively. The screenshot below shows an example: a variable has a type ADC_parameters_t, which is a struct containing (among others) a field channel_t, which is in fact just a uint_least8_t, defined in header su_ctrl.h, line 146.
This code of code navigation (plus jumping from function calls to definitions, and back to callers, etc) is easy to do in Frama-C. But there is currently no way to directly navigate from a given macro/constant to all of its uses.
If you don't need Frama-C's semantic analyses, but only a powerful syntactic exploration and navigation tool, maybe SourceTrail (which has unfortunately been discontinued) could help you. It is a syntactic analysis and navigation tool which does know about preprocessing symbols, and can thus show places of definition, as in the example below:
Currently learning Ada and actually enjoying it, there is a something that bothers me: what's a tagged type? According to Programming in Ada 2012 by John Barnes, it indicates that the instantiated object carries a tag at run time.
I never heard of anything like this in C++ or C I think, so I'm a bit lost. What is it? When do I need it (apparently for having methods and inheritance?)?
It is simply a class. That's a way in Ada to declare the root of a class hierarchy. Another way is to use interfaces.
It is also, at the moment, the way to obtain dot notation for a type (but this will be generalized in Ada 2022).
See https://learn.adacore.com/courses/Ada_For_The_CPP_Java_Developer/chapters/08_Classes_and_Object_Oriented_Programming.html
So you rarely if ever directly manipulate the tag, just the same as vtables are behind the scenes providing the dispatching but you don't need to think about them in C++.
A notable difference with these languages is that T'Class can be used to refer to a whole family of derived types, and it must be used explicitly to achieve dynamic dispatch.
Tag in Ada is much like a Virtual Function Table Pointer in C++. That is, tagged type is the type having this one.
Virtual Function Table Pointer is allocated in the structure/class as soon as it have declared it's first virtual function. In Ada, you just have to declare it explicitly.
Both Ada's Tag and C++'s VFTPtr make a dynamic dispatch available.
Is there any reason to use Qt standard function wrappers like qstrncpy instead of strncpy?
I could not find any hint in documentation. And I'm curious if there is any functional difference. It looks like making code dependent on Qt, even in not mandatory places.
I found this: Qt wrapper for C libraries
But it doesn't answer my question.
These methods are part of Qt's efforts for platform-independence. Qt tries to hide platform differences and use the best each platform has to offer, replicating that functionality on platforms where it is not available. Here is what the documentation of qstrncpy has to say:
A safe strncpy() function.
Copies at most len bytes from src (stopping at len or the terminating '\0' whichever comes first) into dst and returns a pointer to dst. Guarantees that dst is '\0'-terminated. If src or dst is nullptr, returns nullptr immediately.
[âŚ]
Note: When compiling with Visual C++ compiler version 14.00 (Visual C++ 2005) or later, internally the function strncpy_s will be used.
So qstrncpy is safer than strncpy.
The Qt wrappers for these functions are safer than the standard ones because they guarantee the destination string will always be null-terminated. strncpy() does not guarantee this.
In C11, strncpy_s() and other _s() suffixed functions were added as safe string functions. However, they are not available in any C++ standard, they are C-only. The Qt wrappers fix this.
According to the Golang tour, we're provided with the following integer types:
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
In theory, that means we could also have pointers to all of these types as follows:
*int *int8 *int16 *int32 *int64
*uint *uint8 *uint16 *uint32 *uint64 *uintptr
If this is the case, then we already have a pointer to a uint in the form of *uint. That would make uintptr redundant. The official documentation doesn't shed much light on this:
uintptr is an integer type that is large enough to hold the bit pattern of any pointer.
As I understand it, that means that the bit width of a uint is determined at compile time based on the target architecture (typically either 32-bit or 64-bit). It seems logical that the pointer width should scale to the target architecture as well (IE: a 32-bit *uint points to a 32-bit uint). Is that the case in Golang?
Another thought was that maybe uintptr was added to make the syntax less confusing when doing multiple indirection (IE: foo *uinptr vs foo **uint)?
My last thought is that perhaps pointers and integers are incompatible data types in Golang. That would be pretty frustrating since the hardware itself doesn't make any distinction between them. For instance, a "branch to this address" instruction can use the same data from the same register that was just used in an "add this value" instruction.
What's the real point (pun intended) of uintptr?
The short answer is "never use uintptr". đ
The long answer is that uintptr is there to bypass the type system and allow the Go implementors to write Go runtime libraries, including the garbage collection system, in Go, and to call C-callable code including system calls using C pointers that are not handled by Go at all.
If you're acting as an implementorâe.g., providing access to system calls on a new OSâyou'll need uintptr. You will also need to know all the special magic required to use it, such as locking your goroutine to an OS-level thread if the OS is going to do stack-ish things to OS-level threads, for instance. (If you're using it with Go pointers, you may also need to tell the compiler not to move your goroutine stack, which is done with special compile-time directives.)
Edit: as kostix notes in a comment, the runtime system considers an unsafe.Pointer as a reference to an object, which keeps the object alive for GC. It does not consider a uintptr as such a reference. (That is, while unsafe.Pointer has a pointer type, uintptr has integer type.) See also the documentation for the unsafe package.
uintptr is simply an integer representation of a memory address, regardless of the actual type it points to. Sort of like void * in C, or just casting a pointer to an integer. It's purpose is to be used in unsafe black magic, and it is not used in everyday go code.
You are conflating uintptr and *uint. uintptr is used when you're dealing with pointers, it is a datatype that is large enough to hold a pointer. It is mainly used for unsafe memory access, look at the unsafe package. *uint is a pointer to an unsigned integer.
I know that pointers in Go allow mutation of a function's arguments, but wouldn't it have been simpler if they adopted just references (with appropriate const or mutable qualifiers). Now we have pointers and for some built-in types like maps and channels implicit pass by reference.
Am I missing something or are pointers in Go just an unnecessary complication?
Pointers are usefull for several reasons. Pointers allow control over memory layout (affects efficiency of CPU cache). In Go we can define a structure where all the members are in contiguous memory:
type Point struct {
x, y int
}
type LineSegment struct {
source, destination Point
}
In this case the Point structures are embedded within the LineSegment struct. But you can't always embed data directly. If you want to support structures such as binary trees or linked list, then you need to support some kind of pointer.
type TreeNode {
value int
left *TreeNode
right *TreeNode
}
Java, Python etc doesn't have this problem because it does not allow you to embed composite types, so there is no need to syntactically differentiate between embedding and pointing.
Issues with Swift/C# structs solved with Go pointers
A possible alternative to accomplish the same is to differentiate between struct and class as C# and Swift does. But this does have limitations. While you can usually specify that a function takes a struct as an inout parameter to avoid copying the struct, it doesn't allow you to store references (pointers) to structs. This means you can never treat a struct as a reference type when you find that useful e.g. to create a pool allocator (see below).
Custom Memory Allocator
Using pointers you can also create your own pool allocator (this is very simplified with lots of checks removed to just show the principle):
type TreeNode {
value int
left *TreeNode
right *TreeNode
nextFreeNode *TreeNode; // For memory allocation
}
var pool [1024]TreeNode
var firstFreeNode *TreeNode = &pool[0]
func poolAlloc() *TreeNode {
node := firstFreeNode
firstFreeNode = firstFreeNode.nextFreeNode
return node
}
func freeNode(node *TreeNode) {
node.nextFreeNode = firstFreeNode
firstFreeNode = node
}
Swap two values
Pointers also allows you to implement swap. That is swapping the values of two variables:
func swap(a *int, b *int) {
temp := *a
*a = *b
*b = temp
}
Conclusion
Java has never been able to fully replace C++ for systems programming at places such as Google, in part because performance can not be tuned to the same extend due to the lack of ability to control memory layout and usage (cache misses affect performance significantly). Go has aimed to replace C++ in many areas and thus needs to support pointers.
I really like example taken from https://www.golang-book.com/books/intro/8
func zero(x int) {
x = 0
}
func main() {
x := 5
zero(x)
fmt.Println(x) // x is still 5
}
as contrasted with
func zero(xPtr *int) {
*xPtr = 0
}
func main() {
x := 5
zero(&x)
fmt.Println(x) // x is 0
}
Go is designed to be a terse, minimalist language. It therefore started with just values and pointers. Later, by necessity, some reference types (slices, maps, and channels) were added.
The Go Programming Language : Language Design FAQ : Why are maps, slices, and channels references while arrays are values?
"There's a lot of history on that topic. Early on, maps and channels were syntactically pointers and it was impossible to declare or use a non-pointer instance. Also, we struggled with how arrays should work. Eventually we decided that the strict separation of pointers and values made the language harder to use. Introducing reference types, including slices to handle the reference form of arrays, resolved these issues. Reference types add some regrettable complexity to the language but they have a large effect on usability: Go became a more productive, comfortable language when they were introduced."
Fast compilation is a major design goal of the Go programming language; that has its costs. One of the casualties appears to be the ability to mark variables (except for basic compile time constants) and parameters as immutable. It's been requested, but turned down.
golang-nuts : go language. Some feedback and doubts.
"Adding const to the type system forces it to appear everywhere, and
forces one to remove it everywhere if something changes. While there
may be some benefit to marking objects immutable in some way, we don't
think a const type qualifier is to way to go."
References cannot be reassigned, while pointers can. This alone makes pointers useful in many situations where references could not be used.
Rather than answering it in the context of âGoâ, I would answer this question in the context of any language (e.g. C, C++, Go) which implements the concept of "pointers"; and the same reasoning can be applied to âGoâ as well.
There are typically two memory sections where the memory allocation takes place: the Heap Memory and the Stack Memory (letâs not include âglobal section/memoryâ as it would go out of context).
Heap Memory: this is what most of the languages make use of: be it Java, C#, Python⌠But it comes with a penalty called the âGarbage Collectionâ which is a direct performance hit.
Stack Memory: variables can be allocated in the stack memory in languages like C, C++, Go, Java. Stack memory doesnât require garbage collection; hence it is a performant alternative to the heap memory.
But there is a problem: when we allocate an object in the heap memory, we get back a âReferenceâ which can be passed to âmultiple methods/functionsâ and it is through the reference, âmultiple methods/functionsâ can read/update the same object(allocated in the heap memory) directly. Sadly, the same is not true for the stack memory; as we know whenever a stack variable is passed to a method/function, it is âpassed by valueâ(e.g. Java) provided you have the âconcept of pointersâ(as in the case of C, C++, Go).
Here is where pointers come into picture. Pointes let âmultiple methods/functionsâ read/update the data which is placed in the stack memory.
In a nutshell, âpointersâ allow the use of âstack memoryâ instead of the heap memory in order to process variables/structures/objects by âmultiple methods/functionsâ; hence, avoiding performance hit caused by the garbage collection mechanism.
Another reason for introducing pointers in Go could be: Go is ought to be an "Efficient System Programming Language" just like C, C++, Rust etc. and work smoothly with the system calls provided by the underlying Operating System as many of the system call APIs have pointers in their prototype.
One may argue that it can done by introducing a pointer-free layer on top of the system call interface. Yes, it can be done but having pointers would be like acting very close to the system call layer which is trait of a good System Programming Language.