- What a reference actually is - 4 Updates
- What is a `**ppEnum`? - 14 Updates
- CHAR_BIT is not eight - 2 Updates
Juha Nieminen <nospam@thanks.invalid>: Nov 17 09:01AM I have noticed that a lot of C++ programmers have an... well, perhaps the word "incorrect" is too strong, but at least slightly incorrect concept of what a "reference" in C++ is. Not in terms of how the compiler implements it internally, but at the language level. Thus, they tend to explain it to beginners in a way that might not be the best. (They tend to go too much into the internal implementation details that the compiler uses, even if they do this inadvertently, instead of talking at the *language* level, about the semantics.) What I mean with this is that many (perhaps most?) C++ programmers seem to think of C++ references, for all intents and purposes, as "an alternative syntax for pointers". A more limited version of a pointer. Perhaps "a safer alternative syntax for a pointer." While a reference might in practice be internally implemented by the compiler pretty much as if it were a pointer, it shouldn't really be thought as such at the language level. A reference should be thought of as an "alias" for the original variable it's referencing. In almost all situations the reference behaves in the exact same way as the original object it's referencing. Whatever you do to the reference is in practice as if you were doing it directly to the original object. In fact, the syntax for doing things to the original object via the reference is in almost all cases identical to the syntax if you were using the original object directly. The reason why a reference is not a pointer is because of that. For example, you can not use the 'variable[integer]' syntax on a reference if the original object does not support that syntax (and, conversely, you *can* use that syntax if the original object supports it). This shouldn't be thought of as "it's because this is a more limited alternative syntax for pointers", but as "it's because this is an 'alias' for the original object, and behaves the same as that original object does". It's as if you were using the original object directly, and thus all the same syntax support applies. This form of thinking also explains why you can't change a reference to later refer to a different object. It would be like you were trying to make the original object somehow become the other object. Not a *copy* of the other object, but literally the other object. From a semantical perspective that makes no sense. It just doesn't compute. (One could argue that there should be a way to make a reference change what it's an "alias" of, but this is how it was originally designed, so this is how it works.) The advantage of using such an 'alias' reference is that the 'alias' is not a *copy* of the original object. It's just an alias of the original object (which still resides where it originally was created). Thus the reference is usually much more lightweight than taking the original object by copy. While that makes it *similar* to a pointer (and it may internally be implemented as such), it shouldn't really be thought of as one. |
Michael S <already5chosen@yahoo.com>: Nov 17 06:09AM -0800 On Thursday, November 17, 2022 at 11:01:30 AM UTC+2, Juha Nieminen wrote: > object by copy. > While that makes it *similar* to a pointer (and it may internally be > implemented as such), it shouldn't really be thought of as one. For language that is so similar (nearly identical) to C at the level of "virtual machine", as is C++, the concept of reference is just unnecessary. Don't use references in your code except when forced by interfaces that are out of your control! Then people that are going to read and comprehend your code will be thankful. |
Bonita Montero <Bonita.Montero@gmail.com>: Nov 17 07:27PM +0100 References are so simple that I don't understand why to write such a long text about them. |
Paavo Helde <eesnimi@osa.pri.ee>: Nov 18 12:36AM +0200 17.11.2022 16:09 Michael S kirjutas: > Don't use references in your code except when forced by interfaces that > are out of your control! Then people that are going to read and comprehend > your code will be thankful. Aren't most languages similar to C at the level of virtual machine? And isn't it so that a major point of having higher level languages is to provide better abstractions than the virtual machine? With C++, my advise is to not use raw pointers in your code except when forced by interfaces that are out of your control. Prefer references instead, especially const lvalue and non-const rvalue references. |
T <T@invalid.invalid>: Nov 16 03:55PM -0800 On 11/16/22 01:47, Juha Nieminen wrote: > may also be some "you don't have to pay for what you don't use" design > in play here, because if you don't need the new end pointer you can > just pass NULL as the parameter.) The only thing I am not following, is how do I know the length of each item in the array and how many items are in the array. |
scott@slp53.sl.home (Scott Lurndal): Nov 17 12:19AM >The only thing I am not following, is how do I know the >length of each item in the array and how many items are >in the array. You keep track of how many elements you allocated when you create the array. As for the "size of" each element, the 'sizeof' keyword applied to the element will return the size, in bytes. |
Mike Terry <news.dead.person.stones@darjeeling.plus.com>: Nov 17 01:21AM On 16/11/2022 23:55, T wrote: > The only thing I am not following, is how do I know the > length of each item in the array and how many items are > in the array. If you are still talking about C++ HRESULT QueryVolumes( [out] IEnumVdsObject **ppEnum ); then you would seem to have misunderstood Öö Tiib's point - there are no arrays anywhere in there. I'll respond to your earlier post about which bits you understand and don't understand... (but in another thread I suggested that trying to use COM interfaces would require you to learn a load of stuff your might rather avoid, and that's exactly what you're trying to use here!) Regards, Mike. |
T <T@invalid.invalid>: Nov 16 06:01PM -0800 On 11/16/22 17:21, Mike Terry wrote: > HRESULT QueryVolumes( > [out] IEnumVdsObject **ppEnum > ); My (mis) understanding is that **ppEnum points to a pointer that points to an array of HRESULT, which is a 32 bit word. Seems I don't understand. I am expecting the result to give me a long table of volumes. Again, I think I misunderstand. |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Nov 16 06:40PM -0800 > a 32 bit word. Seems I don't understand. > I am expecting the result to give me a long table > of volumes. Again, I think I misunderstand. A (valid non-null) pointer value of type `foo*` always points to a single object of type `foo`. (Handwave: Ignore for now the fact that a valid pointer can point just past the end of an array object.) That single object may or may not be an element of an array of `foo`. If it's just a single object, it can be treated as the lone element of a single-element array. In the example above, ppEnum *might* be intended to be used to manipulate an array of pointers. The declaration isn't enough to tell us that. Given a pointer value that points to an element of an array object, you can access the other elements of that array object by performing pointer arithmetic on the pointer value. (The [] operator is syntactic sugar for this; x[y] means *(x+y).) In C, most array manipulation is done via pointers to the elements of the array. It's less common to have to deal with this in C++ than in C, since C++ defines container classes like std::vector that hide the raw pointer operations. But C++ still inherits just about all of C's (often counterintuitive) pointer and array semantics. Recommended reading: Section 6 of the comp.lang.c FAQ <https://www.c-faq.com/>. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for XCOM Labs void Void(void) { Void(); } /* The recursive call of the void */ |
Mike Terry <news.dead.person.stones@darjeeling.plus.com>: Nov 17 03:36AM On 14/11/2022 10:59, T wrote: >> teaching to compensate ... that we can't do in Usenet thread. > This is what I think I understand and do not. > `*` is a C pointer Yes > C pointer (AAAHHH!) > `HRESULT QueryVolume` is not `HRESULT = QueryVolume(...)`. > It is not a return value from a function. QueryVolume is a COM "method" belonging to the IVdsPack interface. OK, so to use COM you should understand COM basics: - what is COM - basic undertanding of COM architecture: COM objects, interfaces and methods Note: COM does not supply direct C pointers to COM objects - it always provides pointers to INTERFACES, which have METHODS you call to access the associated object. - how interfaces are aquired and released, and at least understand the IUnknown interface, and how interfaces are resource-counted. (Otherwise you will leak resources all over the place.) - how COM reports errors via HRESULT. For disk-management, you are not forced to use COM. There are surely non-COM APIs that would do what you are want? Perhaps using those might be easier... So, you are looking at some documentation at the web link you provided... HRESULT QueryVolumes( [out] IEnumVdsObject **ppEnum ); Best to think of this as a function prototype, descibing/documenting how to use the QueryVolumes method. So it is not an assignment statement. (Like you said.) HMMM - have you spotted that the whole VDS COM apis have been superseded by thw HRESULT is the standard return type used by all COM methods. It is a 32-bit structured value, with some values indicating success, and some failure. See <https://learn.microsoft.com/en-us/windows/win32/com/structure-of-com-error-codes>. So, when you call QueryVolumes it returns an HRESULT to indicate success/failure. You would of course test this following any call. The [out] you can consider to be just documentation, indicating that ppEnum is a pointer to something that is given back to you by the QueryVolumes function (method), i.e. it's an OUT parameter for the call. For the QueryVolumes method, ppEnum points to something of type (IEnumVdsObject *) - this is a new COM interface pointer, pointing to a COM object implementing the IEnumVdsObject interface. You can use that pointer to invoke other methods belonging to the IEnumVdsObject interface. Note: QueryVolumes does not return an array of anything - it returns a new interface you can call to access the various objects to be enumerated. E.g. it has a Next() method that you would call. THAT method can indeed fill an array, but (of course) you need to read and understand the documentation provided for that method... > `HRESULT` is telling me that is the structure of what > the pointer to a pointer (**ppEnum) points to. No, it's the (type of the ) return code from calling the QueryVolumes method. The value indicates primarily whether the method call worked or failed. > I have no idea what `HRESULT` is. I am not sure > how this applies: > https://en.wikipedia.org/wiki/HRESULT#Data_Structure HRESULT is the type that all COM methods return. It is a 32 bit value and in particular the high order bit (bit 31) is the S bit indicating success/failure. Normally you would test this bit by with the SUCCESS or FAILED macros. Something like // iVdsPac is obtained elsewhere HRESULT hr; IEnumVdsObject* pIEnum = NULL; hr = iVdsPac->QueryVolumes (&pIEnum); if (SUCCEEDED(hr)) { // call succeeded, so pIEnum is a new returned interface pointer. // Use the interface, then RELEASE it! // Documentation for the interface (the methods it supports) is at // <https://learn.microsoft.com/en-us/windows/win32/api/vdshwprv/nn-vdshwprv-ienumvdsobject> IUnknown* pIUnknown = NULL; ULONG cFetched = 0; hr = pIEnum->Next (1, &pIUnknown, &cFetched); if (SUCCEEDED(hr)) { // use AND RELEASE pIUnknown, e.g. call QueryInteface to get required interface type etc. // Actually using the interface is omitted from this listing! pIUnknown->Release (); // finished with interface so release it } pIEnum->Release (); ) > I am after both > VDS_E_VOLUME_NOT_HEALTHY (0x8004243EL), and > VDS_E_VOLUME_NOT_A_MIRROR (0x80042445L) No, those are HRESULT failure return codes, as conventionally indicated by the _E_ in the name, and also as indicated by bit 31 of the value being 1. You presumably don't want to fail! What I think you think you want to do is use the IEnumVdsObject interface to step through the objects it enumerates. You should probably read <https://learn.microsoft.com/en-us/windows/win32/vds/working-with-enumeration-objects> and of course before starting on any of this, you need to properly understand the underlying object model for the system (disks?) being modelled, so hopefully you have already read <https://learn.microsoft.com/en-us/windows/win32/vds/vds-object-model> ...except, you probably shouldn't be doing any of this without understanding what you're doing. That's why you should go to a suitable Microsoft development forum, explain what you're trying to do, and follow advice. Or maybe, find an example doing exactly what you want, or get someone to write the code for you! I don't think you have enough background to get going on whatever you're trying to achieve with the route you seem to be taking... [Sorry, I don't have suggestions for specifics for forums etc..] And this whole API is superseded by newer APIs, so you shouldn't be using any of it! :) > Does the "L" stand from 32 bit integer? (To me, > 64 bits is "Long".) Yes, L defines a "long" integer, that's regular C/C++. In MSVC, long integers are 32 bits. 64 bit integers are "long long". > And is bit 31 is used for "Severity" it look a > lot and unsigned integer (cardinal) to me. Yes, bit 31 is severity as shown in the documentation. HRESULT values are unsigned, BUT that hardly matters, as they're not manipulated as integer values - you compare them sometimes if you are checking for one specific error, or you use macros like SUCCEEDED/FAILED to test the bits you need. Regards, Mike. |
Mike Terry <news.dead.person.stones@darjeeling.plus.com>: Nov 17 04:18AM On 17/11/2022 02:01, T wrote: > a 32 bit word. Seems I don't understand. > I am expecting the result to give me a long table > of volumes. Again, I think I misunderstand. Yeah, COM normally returns /interfaces/ on objects and you call those interfaces. You don't access the objects "directly". Enumeration for multiple objects is normally done by getting some kind of enumeration interface which you call to step through whatever is being enumerated. That's how this API works. (That's a COM paradigm, nothing to do with C++ which is what this newsgroup covers...) Viewing the expression like this might help: HRESULT QueryVolumes ( (IEnumVdsObject*) *ppEnum ); ppEnum needs to be a pointer to a single (IEnumVdsObject*) value, which you typically declare on the stack. My other post had fuller illustration, but something like: ... IEnumVdsObject* pIEnum; HRESULT hr = pIface->QueryVolumes ( &pIEnum ); Note the & "address of" C++ operator. (If you need this to be explained, all is lost! :) ) pIEnum has type (IEnumVdsObject*) &pIEnum has type (IEnumVdsObject**) The QueryVolumes call will set the value of pIEnum, assuming it succeeds... pIEnum would be your new interface to call to enumerate [whatever]. The call also sets hr to the return code from the call, which you should test before proceeding - typically it should be tested with the SUCCEEDS macro: if (SUCCEEDED(hr)) ....; // (tests bit 31, but you don't need to know that...) You would call methods on the returned interface to do any stepping through objects etc.. But next you might ask what to do with the IUnknowns that Next() returns and so it will go on. [That's all off topic for this newsgroup, and you shouldn't be doing any of this in the first place, so I won't go any further.] Mike. |
T <T@invalid.invalid>: Nov 16 08:57PM -0800 On 11/16/22 19:36, Mike Terry wrote: > you need. > Regards, > Mike. Wow! Excellent explanation. Thank you! |
Juha Nieminen <nospam@thanks.invalid>: Nov 17 08:25AM > The only thing I am not following, is how do I know the > length of each item in the array and how many items are > in the array. The size (in bytes, if that's what you mean) of each element in the array is just the sizeof the element type. If you have a 'Type*' pointer, then the size of each element in the array is sizeof(Type). A pointer does not carry with itself any information about what it's pointing to (other than the type of that thing). In other words, you cannot know, from the pointer alone, whether it's pointing to a single value or to an array, or what the size of that array is. So to answer your question about how you know how many items there are in the array: You don't. You need to pass the number of elements in the array as a separate value alongside the pointer. (To make this easier you could eg. create a struct that has the pointer and a 'std::size_t' member variable telling how many elements there are in the array pointed to by the pointer.) |
T <T@invalid.invalid>: Nov 17 12:31AM -0800 On 11/17/22 00:25, Juha Nieminen wrote: > (To make this easier you could eg. create a struct that has the pointer > and a 'std::size_t' member variable telling how many elements there > are in the array pointed to by the pointer.) I had mistaken HRESULT as the type that the pointer of the pointer pointed to. HRESULT is just M$'s way of saying it failed or passed. |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Nov 17 01:03PM > The only thing I am not following, is how do I know the > length of each item in the array and how many items are > in the array. I typed this up before seeing Mike's reply. It seems this has been covered more than once, but since I've typed it already... Do you understand the concept of using a pointer to "return" a value from a function? For example int get_some_fancy_hardware_value(long *res); This interface return success (0) or some negative value indicating an error so the return value can't be used to get the fancy value out of the hardware. Instead, it's placed in the long pointed to by the long * argument. You'd write: long hw_val; if (get_some_fancy_hardware_value(&hw_val) >= 0) printf("value=%ld\n", hw_val); else fprintf(stderr, "Could not get hardware value.\n"); Sometimes the value you want to get out is itself a pointer. In these cases that argument will be a pointer to a pointer, as in your example. -- Ben. |
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Nov 17 04:21PM +0100 On 15 Nov 2022 17:28, T wrote: > 4335380480 5 UDF 0 22000.1_X64_EN-US D:\ > 532060160 5 CDFS 0 virtio-win-0.1.225 E:\ > 1694498816 5 CDFS 0 Fedora-Xfce-Live G:\ Oh. Well I don't have any mirrored volumes to test this with, but the docs say that `fsutil volume list` lists /all/ volumes on the system. <url: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/fsutil-volume> "list Lists all of the volumes on the system." --------------------------------------------------------------------- [C:\root\temp] > fsutil volume list Possible volumes and current mount points are: \\?\Volume{8cd6348d-459b-4886-8356-86fd8fc094db}\ C:\ \\?\Volume{a4069431-b4bd-4e1d-af34-e433ebccf585}\ \\?\Volume{fe18d3d2-8a44-4b3a-86cf-ce555ee308dd}\ D:\ \\?\Volume{511a54e0-b6d4-49b9-8000-e202ce217be7}\ [C:\root\temp] > wmic volume list brief Capacity DriveType FileSystem FreeSpace Label Name 510770802688 3 NTFS 108444856320 C:\ 1043329024 3 NTFS 317726720 WinRE_DRV \\?\Volume{a4069431-b4bd-4e1d-af34-e433ebccf585}\ 8001427599360 3 NTFS 3994988654592 Seagate Expansion Drive D:\ 268435456 3 FAT32 231571456 SYSTEM \\?\Volume{511a54e0-b6d4-49b9-8000-e202ce217be7}\ --------------------------------------------------------------------- Disclaimer: I only tested that that sub-command doesn't require elevated access in Windows 11. I remember that fsutil was one of the things totally "security"-fouled up in Windows Vista. It's hard to keep track of Microsoft's endless bug introductions, partial bug fixes and willy nilly changes of things, and I don't even try that any more, so. - Alf |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Nov 17 10:17AM -0800 > pointing to (other than the type of that thing). In other words, you > cannot know, from the pointer alone, whether it's pointing to a single > value or to an array, or what the size of that array is. A (valid non-null) pointer to FOO points to a single object (not value) of type FOO. It never points to an array, unless FOO happens to be an array type. The single FOO object that it points to may or may not be an element of an array of FOO (and if it's really just a single object, it can be treated as the sole element of a 1-element array of FOO). The think you cannot know is the size of the array of which the pointed-to FOO object may be an element. It's not uncommon to refer informally to a pointer to the initial element of an array as a pointer to the array, but pointers to arrays are a distinct thing. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for XCOM Labs void Void(void) { Void(); } /* The recursive call of the void */ |
T <T@invalid.invalid>: Nov 17 10:28AM -0800 On 11/17/22 05:03, Ben Bacarisse wrote: > else fprintf(stderr, "Could not get hardware value.\n"); > Sometimes the value you want to get out is itself a pointer. In these > cases that argument will be a pointer to a pointer, as in your example. I found this example that follows what you guys have been trying to get through my thick skull: if (!WTSEnumerateSessions(WTS_CURRENT_SERVER, 0, 1, &pwsi, &dwCount)) { Report(_T("WTSEnumerateSessions failed with error code %d\n"), GetLastError()); return 0; } for (DWORD i = 0; i < dwCount; i++) { if (pwsi[i].State == WTSActive) { dwSession = pwsi[i].SessionId; break; } } WTSFreeMemory(pwsi); |
David Brown <david.brown@hesbynett.no>: Nov 17 11:04AM +0100 On 16/11/2022 15:24, Michael S wrote: > It is possible to find technical justifications as well, in their respective > architectures, micro-architectures and especially in sets of peripheral, > but all that is secondary to the will of manufacturer. It is a DSP, not a microcontroller - mostly because /I/ decide to call them that way :-) Of course there is no precise and universally agreed-upon distinction. Typical microcontroller traits are integrated peripherals (UART, I²C, SPI, PWM, Timers, CAN, etc.) and integrated memory. From that viewpoint, they are microcontrollers. Typical DSP traits are specialised processor cores with instructions and hardware targeting maximum throughput of FIR, IIR, FFT and other "DSP" algorithms, often at the expense of convenience of more "normal" code. The core of these devices (at least on the TMS320F24x device I have used) is clearly DSP oriented. It is very efficient for DSP style code, but a mess for more "random" stuff - trying to deal with 8-bit data, for example, is horrible. Probably the best way to describe these devices is microcontrollers with DSP cores. |
Muttley@dastardlyhq.com: Nov 17 04:40PM On Thu, 17 Nov 2022 11:04:42 +0100 >Of course there is no precise and universally agreed-upon distinction. >Typical microcontroller traits are integrated peripherals (UART, I²C, >SPI, PWM, Timers, CAN, etc.) and integrated memory. From that To be fair a lot of microcontrollers have those too. I would define a DSP as something that can do ADC and/or DAC itself, ie it can process external data directly and the TI chips AFAIK can do that. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment